Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

XFuXMPlayer.cpp

Go to the documentation of this file.
00001 /*! \file 
00002  * X-Forge Util <br>
00003  * Copyright 2000-2003 Fathammer Ltd
00004  * 
00005  * \brief XM player.
00006  * \todo doxygen comments
00007  * \todo Panning envelope support on "key off"
00008  * \todo Random waveform support for vibrato and tremolo
00009  * \todo Set glissando control -command
00010  * \todo Set envelope position -command
00011  * 
00012  * $Id: XFuXMPlayer.cpp,v 1.41 2003/06/18 13:18:44 jetro Exp $
00013  * $Date: 2003/06/18 13:18:44 $
00014  * $Revision: 1.41 $
00015  */
00016 #include <stdlib.h> // \ needed for
00017 #include <stdarg.h> // / va_args
00018 #include <xfcore/XFcCore.h>
00019 #include <xfcore/XFcAudioFlags.h>
00020 #include <xfcore/XFcLinkedList.h>
00021 #include <xfutil/XFuXMPlayer.h>
00022 #include <xfutil/XFuXMPlayer_internal.h>
00023 #include <xfutil/XFuXMPlayerEventHandler.h>
00024 
00025 
00026 const static INT32 linearFrequencyTable[768] =
00027 {
00028     535232,534749,534266,533784,533303,532822,532341,531861,
00029     531381,530902,530423,529944,529466,528988,528511,528034,
00030     527558,527082,526607,526131,525657,525183,524709,524236,
00031     523763,523290,522818,522346,521875,521404,520934,520464,
00032     519994,519525,519057,518588,518121,517653,517186,516720,
00033     516253,515788,515322,514858,514393,513929,513465,513002,
00034     512539,512077,511615,511154,510692,510232,509771,509312,
00035     508852,508393,507934,507476,507018,506561,506104,505647,
00036     505191,504735,504280,503825,503371,502917,502463,502010,
00037     501557,501104,500652,500201,499749,499298,498848,498398,
00038     497948,497499,497050,496602,496154,495706,495259,494812,
00039     494366,493920,493474,493029,492585,492140,491696,491253,
00040     490809,490367,489924,489482,489041,488600,488159,487718,
00041     487278,486839,486400,485961,485522,485084,484647,484210,
00042     483773,483336,482900,482465,482029,481595,481160,480726,
00043     480292,479859,479426,478994,478562,478130,477699,477268,
00044     476837,476407,475977,475548,475119,474690,474262,473834,
00045     473407,472979,472553,472126,471701,471275,470850,470425,
00046     470001,469577,469153,468730,468307,467884,467462,467041,
00047     466619,466198,465778,465358,464938,464518,464099,463681,
00048     463262,462844,462427,462010,461593,461177,460760,460345,
00049     459930,459515,459100,458686,458272,457859,457446,457033,
00050     456621,456209,455797,455386,454975,454565,454155,453745,
00051     453336,452927,452518,452110,451702,451294,450887,450481,
00052     450074,449668,449262,448857,448452,448048,447644,447240,
00053     446836,446433,446030,445628,445226,444824,444423,444022,
00054     443622,443221,442821,442422,442023,441624,441226,440828,
00055     440430,440033,439636,439239,438843,438447,438051,437656,
00056     437261,436867,436473,436079,435686,435293,434900,434508,
00057     434116,433724,433333,432942,432551,432161,431771,431382,
00058     430992,430604,430215,429827,429439,429052,428665,428278,
00059     427892,427506,427120,426735,426350,425965,425581,425197,
00060     424813,424430,424047,423665,423283,422901,422519,422138,
00061     421757,421377,420997,420617,420237,419858,419479,419101,
00062     418723,418345,417968,417591,417214,416838,416462,416086,
00063     415711,415336,414961,414586,414212,413839,413465,413092,
00064     412720,412347,411975,411604,411232,410862,410491,410121,
00065     409751,409381,409012,408643,408274,407906,407538,407170,
00066     406803,406436,406069,405703,405337,404971,404606,404241,
00067     403876,403512,403148,402784,402421,402058,401695,401333,
00068     400970,400609,400247,399886,399525,399165,398805,398445,
00069     398086,397727,397368,397009,396651,396293,395936,395579,
00070     395222,394865,394509,394153,393798,393442,393087,392733,
00071     392378,392024,391671,391317,390964,390612,390259,389907,
00072     389556,389204,388853,388502,388152,387802,387452,387102,
00073     386753,386404,386056,385707,385359,385012,384664,384317,
00074     383971,383624,383278,382932,382587,382242,381897,381552,
00075     381208,380864,380521,380177,379834,379492,379149,378807,
00076     378466,378124,377783,377442,377102,376762,376422,376082,
00077     375743,375404,375065,374727,374389,374051,373714,373377,
00078     373040,372703,372367,372031,371695,371360,371025,370690,
00079     370356,370022,369688,369355,369021,368688,368356,368023,
00080     367691,367360,367028,366697,366366,366036,365706,365376,
00081     365046,364717,364388,364059,363731,363403,363075,362747,
00082     362420,362093,361766,361440,361114,360788,360463,360137,
00083     359813,359488,359164,358840,358516,358193,357869,357547,
00084     357224,356902,356580,356258,355937,355616,355295,354974,
00085     354654,354334,354014,353695,353376,353057,352739,352420,
00086     352103,351785,351468,351150,350834,350517,350201,349885,
00087     349569,349254,348939,348624,348310,347995,347682,347368,
00088     347055,346741,346429,346116,345804,345492,345180,344869,
00089     344558,344247,343936,343626,343316,343006,342697,342388,
00090     342079,341770,341462,341154,340846,340539,340231,339924,
00091     339618,339311,339005,338700,338394,338089,337784,337479,
00092     337175,336870,336566,336263,335959,335656,335354,335051,
00093     334749,334447,334145,333844,333542,333242,332941,332641,
00094     332341,332041,331741,331442,331143,330844,330546,330247,
00095     329950,329652,329355,329057,328761,328464,328168,327872,
00096     327576,327280,326985,326690,326395,326101,325807,325513,
00097     325219,324926,324633,324340,324047,323755,323463,323171,
00098     322879,322588,322297,322006,321716,321426,321136,320846,
00099     320557,320267,319978,319690,319401,319113,318825,318538,
00100     318250,317963,317676,317390,317103,316817,316532,316246,
00101     315961,315676,315391,315106,314822,314538,314254,313971,
00102     313688,313405,313122,312839,312557,312275,311994,311712,
00103     311431,311150,310869,310589,310309,310029,309749,309470,
00104     309190,308911,308633,308354,308076,307798,307521,307243,
00105     306966,306689,306412,306136,305860,305584,305308,305033,
00106     304758,304483,304208,303934,303659,303385,303112,302838,
00107     302565,302292,302019,301747,301475,301203,300931,300660,
00108     300388,300117,299847,299576,299306,299036,298766,298497,
00109     298227,297958,297689,297421,297153,296884,296617,296349,
00110     296082,295815,295548,295281,295015,294749,294483,294217,
00111     293952,293686,293421,293157,292892,292628,292364,292100,
00112     291837,291574,291311,291048,290785,290523,290261,289999,
00113     289737,289476,289215,288954,288693,288433,288173,287913,
00114     287653,287393,287134,286875,286616,286358,286099,285841,
00115     285583,285326,285068,284811,284554,284298,284041,283785,
00116     283529,283273,283017,282762,282507,282252,281998,281743,
00117     281489,281235,280981,280728,280475,280222,279969,279716,
00118     279464,279212,278960,278708,278457,278206,277955,277704,
00119     277453,277203,276953,276703,276453,276204,275955,275706,
00120     275457,275209,274960,274712,274465,274217,273970,273722,
00121     273476,273229,272982,272736,272490,272244,271999,271753,
00122     271508,271263,271018,270774,270530,270286,270042,269798,
00123     269555,269312,269069,268826,268583,268341,268099,267857
00124 };
00125 
00126 
00127 #define ABS(x) (((x) < 0) ? -(x) : (x))
00128 
00129 #define interpolateLinear8(ch, val1, val2) \
00130     val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
00131     \
00132     if ((ch.mPointer + FP_VALUE) < ch.mLength) \
00133         val2 = *((INT8 *)ch.mOffset + ((ch.mPointer + FP_VALUE) >> FP_BITS)); \
00134     else \
00135         val2 = 0;
00136 
00137 
00138 #define interpolateLinear16(ch, val1, val2) \
00139     val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
00140     \
00141     if ((ch.mPointer + FP_VALUE) < ch.mLength) \
00142         val2 = *((INT16 *)ch.mOffset + ((ch.mPointer + FP_VALUE) >> FP_BITS)); \
00143     else \
00144         val2 = 0;
00145 
00146 
00147 #define interpolateLinearForwardLoop8(ch, val1, val2, temp) \
00148     val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
00149     \
00150     temp = (ch.mPointer + FP_VALUE); \
00151     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
00152         temp = ch.mLoopStart + (temp - (ch.mLoopEnd + FP_VALUE)); \
00153     \
00154     val2 = *((INT8 *)ch.mOffset + (temp >> FP_BITS));
00155 
00156 
00157 #define interpolateLinearForwardLoop16(ch, val1, val2, temp) \
00158     val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
00159     \
00160     temp = (ch.mPointer + FP_VALUE); \
00161     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
00162         temp = ch.mLoopStart + (temp - (ch.mLoopEnd + FP_VALUE)); \
00163     \
00164     val2 = *((INT16 *)ch.mOffset + (temp >> FP_BITS));
00165 
00166 
00167 #define interpolateLinearBidirectionalLoop8(ch, val1, val2, temp) \
00168     val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
00169     \
00170     temp = (ch.mPointer + FP_VALUE); \
00171     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
00172         temp = ch.mLoopEnd - (temp - (ch.mLoopEnd + FP_VALUE)); \
00173     \
00174     val2 = *((INT8 *)ch.mOffset + (temp >> FP_BITS)); \
00175 
00176 
00177 #define interpolateLinearBidirectionalLoop16(ch, val1, val2, temp) \
00178     val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS)); \
00179     \
00180     temp = (ch.mPointer + FP_VALUE); \
00181     if ((temp >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
00182         temp = ch.mLoopEnd - (temp - (ch.mLoopEnd + FP_VALUE)); \
00183     \
00184     val2 = *((INT16 *)ch.mOffset + (temp >> FP_BITS));
00185 
00186 
00187 #define addPointer(ch) \
00188     ch.mPointer += ch.mSpeed; \
00189     if (ch.mPointer > (ch.mLength - FP_VALUE)) \
00190         ch.mIsSample = 0;
00191 
00192 
00193 #define addPointerForwardLoop(ch) \
00194     ch.mPointer += ch.mSpeed; \
00195     if ((ch.mPointer >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
00196         ch.mPointer = ch.mLoopStart + (ch.mPointer - (ch.mLoopEnd + FP_VALUE));
00197 
00198 
00199 #define addPointerBidirectionalLoop(ch) \
00200     if (ch.mDirection == 1) \
00201     { \
00202         ch.mPointer += ch.mSpeed; \
00203         \
00204         if ((ch.mPointer >> FP_BITS) > (ch.mLoopEnd >> FP_BITS)) \
00205         { \
00206             ch.mDirection = -1; \
00207             ch.mPointer = ch.mLoopEnd - (ch.mPointer - (ch.mLoopEnd + FP_VALUE)); \
00208         } \
00209     } \
00210     else \
00211     { \
00212         ch.mPointer -= ch.mSpeed; \
00213         \
00214         if ((ch.mPointer >> FP_BITS) < (ch.mLoopStart >> FP_BITS)) \
00215         { \
00216             ch.mDirection = 1; \
00217             ch.mPointer = ch.mLoopStart + (ch.mLoopStart - ch.mPointer); \
00218         } \
00219     }
00220 
00221 
00222 //#define OUTPUT_XM_INFO
00223 
00224 #ifdef OUTPUT_XM_INFO
00225 static const char *notes[12] =
00226     {"C-","C#","D-","D#","E-","F-","F#","G-","G#","A-","A#","B-"};
00227 #endif // OUTPUT_XM_INFO
00228 
00229 
00230 void DebugPrint(XFcFile *aTextout, char *aFmt, ...) {
00231 #if !defined(XFC_PLATFORM_EPOC) && !defined(XFC_PLATFORM_PALM)
00232     if (aTextout != NULL)
00233     {
00234         va_list ap; 
00235         static char buffer[10240];  
00236         va_start(ap, aFmt);  
00237         vsprintf(buffer, aFmt, ap);  
00238         aTextout->write(buffer, 1, XFcStringToolkit::getLength(buffer));
00239         va_end(ap);
00240     }
00241 #endif // XFC_PLATFORM_EPOC
00242 }
00243 
00244 
00245 void XFuXMPlayer::dumpSongParameters(XFcFile *aTextout)
00246 {
00247     INT i = 0, x;
00248 
00249     DebugPrint(aTextout, "\n\nParameters for current mSong. \n\n");
00250     DebugPrint(aTextout, "module type: %s\n", mSong.mTypeString);
00251     DebugPrint(aTextout, "song length: %d\n", mSong.mSongLength);
00252     DebugPrint(aTextout, "song restart: %d\n", mSong.mRestartPosition);
00253     DebugPrint(aTextout, "order: ");
00254 
00255     for (i = 0; i < mSong.mSongLength; i++)
00256         DebugPrint(aTextout, "%d ", mSong.mOrderTable[i]);
00257 
00258     DebugPrint(aTextout, "\n");
00259     DebugPrint(aTextout, "nof patterns: %d\n", mSong.mNbPatterns);
00260     DebugPrint(aTextout, "nof channels: %d\n", mSong.mNbChannels);
00261     DebugPrint(aTextout, "nof instrument: %d\n", mSong.mNbInstruments);
00262     DebugPrint(aTextout, "tempo: %d\n", mSong.mTempo);
00263     DebugPrint(aTextout, "bpm: %d\n", mSong.mBpm);
00264     DebugPrint(aTextout, "\nmInstruments: \n");
00265 
00266     for (i = 0; i < mSong.mNbInstruments; i++)
00267     {
00268         XFuXMInstrument &ins = mInstruments[i];
00269 
00270         DebugPrint(aTextout, "\ninstr %02X \n", i);
00271 
00272         DebugPrint(aTextout, "is vibrato? %d \n", ins.mIsVibrato);
00273         DebugPrint(aTextout, "vibratoType: %d \n", ins.mVibratoType);
00274         DebugPrint(aTextout, "vibratoSweep: %d \n", ins.mVibratoSweep);
00275         DebugPrint(aTextout, "vibratoDepth: %d \n", ins.mVibratoDepth);
00276         DebugPrint(aTextout, "vibratoRate: %d \n", ins.mVibratoRate);
00277 
00278         DebugPrint(aTextout, "\nvolume envelope: \n");
00279         DebugPrint(aTextout, "  fadeout: %d \n", ins.mVolumeFadeout);
00280         DebugPrint(aTextout, "  end point: %d\n", ins.mVolEnvEnd);  
00281         DebugPrint(aTextout, "  type: %d\n", ins.mVolEnvType);
00282         DebugPrint(aTextout, "  on? %d\n", (ins.mVolEnvType & ENV_ON));
00283         DebugPrint(aTextout, "  sustain? %d\n",
00284                    (ins.mVolEnvType & ENV_SUSTAIN));
00285         DebugPrint(aTextout, "  sustain point: %d\n", (ins.mVolEnvSustain));
00286         DebugPrint(aTextout, "  loop? %d\n", (ins.mVolEnvType & ENV_LOOP));
00287         DebugPrint(aTextout, "  loop start: %d\n", ins.mVolEnvLoopStart);
00288         DebugPrint(aTextout, "  loop end: %d\n", ins.mVolEnvLoopEnd);
00289         DebugPrint(aTextout, "  envelope: ");
00290 
00291         for (x = 0; x < ins.mVolEnvEnd; x++)
00292             DebugPrint(aTextout,"%2.2f ", ins.mVolumeEnvelope[x]);
00293 
00294         DebugPrint(aTextout, "\n"); 
00295         DebugPrint(aTextout, "\npanning envelope: \n");
00296         DebugPrint(aTextout, "  on? %d\n", (ins.mPanEnvType & ENV_ON));
00297         DebugPrint(aTextout, "  loop? %d\n", (ins.mPanEnvType & ENV_LOOP));
00298         DebugPrint(aTextout, "  loop start: %d\n", ins.mPanEnvLoopStart);
00299         DebugPrint(aTextout, "  loop end: %d\n", ins.mPanEnvLoopEnd);
00300         DebugPrint(aTextout, "  envelope: ");
00301 
00302         for (x = 0; x < ins.mPanEnvEnd; x++)
00303             DebugPrint(aTextout, "%d ", ins.mPanningEnvelope[x]);
00304 
00305         DebugPrint(aTextout,"\n-----\n");   
00306     }
00307 }
00308 
00309 
00310 INT32 XFuXMPlayer::loadXM(const CHAR *aFilename, XFcFile *aTextout)
00311 {
00312     XFcFile *f;
00313 
00314     INT i, j, k, ii;
00315     FLOAT32 y1, y2, dx;
00316     INT xx, x1, x2;
00317 
00318     XFuXMFormatInstrumentHeader xmInstrumentHeader;
00319     XFuXMFormatInstrument xmInstrument;
00320     XFuXMFormatSample xmSample;
00321 
00322     DebugPrint(aTextout, "Fathammer XM-player debug file.\n");
00323     DebugPrint(aTextout, "Opening %s.\n", aFilename);
00324 
00325     f = XFcFile::open(aFilename, "rb");
00326     if (f == 0) {
00327         DebugPrint(aTextout, "error opening file.\n");
00328         if (aTextout != NULL) aTextout->close();
00329         return 1;
00330     }
00331 
00332     DebugPrint(aTextout, "opened.\n");
00333 
00334     DebugPrint(aTextout, "reading header...\n\n");
00335     f->read(mXMHeader.mIdString, 17, sizeof(UINT8));
00336     f->read(mXMHeader.mModuleName, 20, sizeof(UINT8));
00337     f->readUINT8(mXMHeader.mH1A);
00338     f->read(mXMHeader.mTrackerName, 20, sizeof(UINT8));
00339     f->readUINT16(mXMHeader.mVersion);
00340 
00341     f->readUINT32(mXMHeader.mHeaderSize);
00342 
00343     f->readUINT16(mXMHeader.mSongLength);
00344     f->readUINT16(mXMHeader.mRestartPosition);
00345     f->readUINT16(mXMHeader.mNbChannels);
00346     f->readUINT16(mXMHeader.mNbPatterns);
00347     f->readUINT16(mXMHeader.mNbInstruments);
00348 
00349     f->readUINT16(mXMHeader.mFlags);
00350 
00351     f->readUINT16(mXMHeader.mTempo);
00352     f->readUINT16(mXMHeader.mBpm);
00353 
00354     f->read(mXMHeader.mOrderTable, 256, sizeof(UINT8));
00355 
00356     DebugPrint(aTextout, "id string: %s\n", mXMHeader.mIdString);
00357     DebugPrint(aTextout, "module name: %s\n", mXMHeader.mModuleName);
00358     DebugPrint(aTextout, "h1A: %d\n", mXMHeader.mH1A);
00359     DebugPrint(aTextout, "tracker name: %s\n", mXMHeader.mTrackerName);
00360     DebugPrint(aTextout, "tracker version: %d\n", mXMHeader.mVersion);
00361     DebugPrint(aTextout, "header size: %d\n", mXMHeader.mHeaderSize);
00362     DebugPrint(aTextout, "song length: %d\n", mXMHeader.mSongLength);
00363     DebugPrint(aTextout, "restart pos: %d\n", mXMHeader.mRestartPosition);
00364     DebugPrint(aTextout, "nof mChannels: %d\n", mXMHeader.mNbChannels);
00365     DebugPrint(aTextout, "nof patterns: %d\n", mXMHeader.mNbPatterns);
00366     DebugPrint(aTextout, "nof instrument: %d\n", mXMHeader.mNbInstruments);
00367     DebugPrint(aTextout, "flags: %d\n", mXMHeader.mFlags);
00368     DebugPrint(aTextout, "tempo: %d\n", mXMHeader.mTempo);
00369     DebugPrint(aTextout, "bpm: %d\n", mXMHeader.mBpm);
00370     DebugPrint(aTextout, "ordertable: \n");
00371 
00372     // Allocate memory for order list
00373     mSong.mOrderTable = new UINT8[mXMHeader.mSongLength];
00374     memset(mSong.mOrderTable, 0, mXMHeader.mSongLength * sizeof(UINT8));
00375 
00376     for (i = 0; i < mXMHeader.mSongLength; i++)
00377     {
00378         DebugPrint(aTextout, "%2X->%2X\n", i, mXMHeader.mOrderTable[i]);
00379         mSong.mOrderTable[i] = mXMHeader.mOrderTable[i];
00380     }
00381 
00382     // Save song header
00383     mSong.mTypeString = "XM-module";
00384     mSong.mNbChannels = mXMHeader.mNbChannels;
00385     mSong.mNbPatterns = mXMHeader.mNbPatterns;
00386     mSong.mNbInstruments = mXMHeader.mNbInstruments;
00387     mSong.mSongLength = mXMHeader.mSongLength;
00388     mSong.mRestartPosition = mXMHeader.mRestartPosition;
00389     mSong.mBpm = mXMHeader.mBpm;
00390     mSong.mTempo = mXMHeader.mTempo;
00391     
00392     // Allocate memory for mChannels
00393     mChannels = new XFuXMChannel[mSong.mNbChannels];
00394     memset(mChannels, 0, mSong.mNbChannels * sizeof(XFuXMChannel));
00395 
00396     // Read pattern headers and pattern data
00397     DebugPrint(aTextout, "\npatterns:\n\n");
00398     
00399     // Allocate memory for pattern headers
00400     mXMPatternHeaders = new XFuXMFormatPatternHeader[mXMHeader.mNbPatterns];
00401     memset(mXMPatternHeaders, 0, 
00402         mXMHeader.mNbPatterns * sizeof(XFuXMFormatPatternHeader));
00403 
00404     // Allocate memory for pattern data blocks
00405     mPatternData = new XFuXMPattern[mXMHeader.mNbPatterns];
00406     memset(mPatternData, 0, mXMHeader.mNbPatterns * sizeof(XFuXMPattern));
00407 
00408     for (i = 0; i < mXMHeader.mNbPatterns; i++)
00409     {
00410         DebugPrint(aTextout, "pattern %d \n", i);
00411 
00412         f->readUINT32(mXMPatternHeaders[i].mHeaderLength);
00413         f->readUINT8(mXMPatternHeaders[i].mPackingType);
00414         f->readUINT16(mXMPatternHeaders[i].mNbRows);
00415         f->readUINT16(mXMPatternHeaders[i].mSize);
00416 
00417         DebugPrint(aTextout, "header length: %d \n",
00418                    mXMPatternHeaders[i].mHeaderLength);
00419         DebugPrint(aTextout, "packing type: %d \n",
00420                    mXMPatternHeaders[i].mPackingType);
00421         DebugPrint(aTextout, "nof rows: %d \n", mXMPatternHeaders[i].mNbRows);
00422         DebugPrint(aTextout, "size: %d \n\n", mXMPatternHeaders[i].mSize);
00423 
00424         if (mXMPatternHeaders[i].mSize > 0)
00425         {
00426             // Allocate memory for actual pattern data
00427             mPatternData[i].mData = new UINT8[mXMPatternHeaders[i].mSize];
00428             mPatternData[i].mRows = new UINT32[mXMPatternHeaders[i].mNbRows];
00429             f->read(mPatternData[i].mData, mXMPatternHeaders[i].mSize, 1);
00430 
00431             UINT8 b = 0;
00432             UINT32 p = 0;
00433             for (j = 0; j < mXMPatternHeaders[i].mNbRows; j++)
00434             {
00435                 mPatternData[i].mRows[j] = p;
00436 
00437                 for (k = 0; k < mSong.mNbChannels; k++)
00438                 {
00439                     b = *(mPatternData[i].mData + p++);
00440 
00441                     if ((b & 128) == 128) {
00442                         // Packed atom
00443                         if ((b & 1) == 1) p++;
00444                         if ((b & 2) == 2) p++;
00445                         if ((b & 4) == 4) p++;
00446                         if ((b & 8) == 8) p++;
00447                         if ((b & 16) == 16) p++;
00448                     }
00449                     else
00450                     {
00451                         // Normal atom
00452                         p += 4;
00453                     }
00454                 }
00455             }
00456         }
00457     }
00458 
00459     // Allocate memory for mInstruments
00460     mInstruments = new XFuXMInstrument[mXMHeader.mNbInstruments];
00461     memset(mInstruments, 0, mXMHeader.mNbInstruments * sizeof(XFuXMInstrument));
00462 
00463     // Read mInstruments
00464     DebugPrint(aTextout, "mInstruments \n\n");
00465     for (i = 0; i < mXMHeader.mNbInstruments; i++)
00466     {
00467         DebugPrint(aTextout, "instrument %02x \n", i);
00468 
00469         XFuXMInstrument &ins = mInstruments[i];
00470 
00471         memset(&xmInstrumentHeader, 0, sizeof(XFuXMFormatInstrumentHeader));
00472 
00473         f->readUINT32(xmInstrumentHeader.mSize);
00474         f->read(xmInstrumentHeader.mInstrumentName, 22, sizeof(UINT8));
00475         f->readUINT8(xmInstrumentHeader.mType);
00476         f->readUINT16(xmInstrumentHeader.mNbSamples);
00477 
00478         ins.mNbSamples = xmInstrumentHeader.mNbSamples;
00479 
00480         DebugPrint(aTextout, "size: %d \n", xmInstrumentHeader.mSize);
00481         DebugPrint(aTextout, "name: %s \n", xmInstrumentHeader.mInstrumentName);
00482         DebugPrint(aTextout, "type: %d \n", xmInstrumentHeader.mType);
00483         DebugPrint(aTextout, "nof samples: %d \n",
00484                    xmInstrumentHeader.mNbSamples);
00485 
00486         // sizeof(xmInstrumentHeader) could return an ALIGNED value
00487         INT32 skip = xmInstrumentHeader.mSize - 29;
00488 
00489         if (xmInstrumentHeader.mNbSamples > 0)
00490         {
00491             memset(&xmInstrument, 0, sizeof(XFuXMFormatInstrument));
00492 
00493             f->readUINT32(xmInstrument.mSampleHeaderSize);
00494             f->read(xmInstrument.mKeyboard, 96, sizeof(UINT8));
00495             f->read(xmInstrument.mVolumeEnvelope, 24, sizeof(UINT16));
00496             f->read(xmInstrument.mPanningEnvelope, 24, sizeof(UINT16));
00497             f->readUINT8(xmInstrument.mNbVolEnvPoints);
00498             f->readUINT8(xmInstrument.mNbPanEnvPoints);
00499             f->readUINT8(xmInstrument.mVolEnvSustain);
00500             f->readUINT8(xmInstrument.mVolEnvLoopStart);
00501             f->readUINT8(xmInstrument.mVolEnvLoopEnd);
00502             f->readUINT8(xmInstrument.mPanEnvSustain);
00503             f->readUINT8(xmInstrument.mPanEnvLoopStart);
00504             f->readUINT8(xmInstrument.mPanEnvLoopEnd);
00505             f->readUINT8(xmInstrument.mVolEnvType);
00506             f->readUINT8(xmInstrument.mPanEnvType);
00507 
00508             f->readUINT8(xmInstrument.mVibratoType);
00509             f->readUINT8(xmInstrument.mVibratoSweep);
00510             f->readUINT8(xmInstrument.mVibratoDepth);
00511             f->readUINT8(xmInstrument.mVibratoRate);
00512 
00513             f->readUINT16(xmInstrument.mVolumeFadeout);
00514 
00515             f->readUINT16(xmInstrument.mReserved);
00516 
00517             // sizeof(xmInstrument) could return an ALIGNED value
00518             skip -= 214;
00519             f->seek(skip, SEEK_CUR);
00520 
00521             // Allocate memory for samples in instrument
00522             ins.mSamples = new XFuXMSample[xmInstrumentHeader.mNbSamples];
00523             memset(ins.mSamples, 0, xmInstrumentHeader.mNbSamples * sizeof(XFuXMSample));
00524 
00525             for (j = 0; j < xmInstrumentHeader.mNbSamples; j++)
00526             {
00527                 XFuXMSample &smp = ins.mSamples[j];
00528 
00529                 memset(&xmSample, 0, sizeof(XFuXMFormatSample));
00530 
00531                 f->readUINT32(xmSample.mSampleLength);
00532                 f->readUINT32(xmSample.mLoopStart);
00533                 f->readUINT32(xmSample.mLoopLength);
00534                 f->readUINT8(xmSample.mVolume);
00535                 f->readINT8(xmSample.mFinetune);
00536                 f->readUINT8(xmSample.mType);
00537                 f->readUINT8(xmSample.mPan);
00538                 f->readINT8(xmSample.mRelativeNote);
00539                 f->readUINT8(xmSample.mReserved);
00540 
00541                 f->read(xmSample.mSampleName, 22, sizeof(UINT8));
00542 
00543                 DebugPrint(aTextout, "Allocating %d bytes for sample %02X in "
00544                            "instrument %02X\n", xmSample.mSampleLength, j, i);
00545                 DebugPrint(aTextout, "sample length %d \n",
00546                            xmSample.mSampleLength);
00547                 DebugPrint(aTextout, "loop start %d \n", xmSample.mLoopStart);
00548                 DebugPrint(aTextout, "loop length %d \n", xmSample.mLoopLength);
00549                 DebugPrint(aTextout, "volume %d \n", xmSample.mVolume);
00550                 DebugPrint(aTextout, "finetune %d \n", xmSample.mFinetune);
00551                 DebugPrint(aTextout, "type %d \n", xmSample.mType);
00552                 DebugPrint(aTextout, "  loop fwd? %d\n",
00553                            (xmSample.mType & LOOP_FORWARD) ? 1 : 0);
00554                 DebugPrint(aTextout, "  loop pingpong? %d\n",
00555                            (xmSample.mType & LOOP_PINGPONG) ? 1 : 0);
00556                 DebugPrint(aTextout, "  16 bit? %d\n",
00557                            (xmSample.mType & XMFORMAT_SAMPLE_16BIT) ? 1 : 0);
00558                 DebugPrint(aTextout, "pan %d \n", xmSample.mPan);
00559                 DebugPrint(aTextout, "relative note %d \n",
00560                            xmSample.mRelativeNote);
00561                 xmSample.mSampleName[21] = '\0';
00562                 DebugPrint(aTextout, "sample name %s \n", xmSample.mSampleName);
00563 
00564                 smp.mSize = xmSample.mSampleLength;
00565                 smp.mVolume = xmSample.mVolume;
00566                 smp.mPan = xmSample.mPan;
00567                 smp.mLoopForward = (UINT8)((xmSample.mType & LOOP_FORWARD) ? 1 : 0);
00568                 smp.mLoopPingpong = (UINT8)((xmSample.mType & LOOP_PINGPONG) ? 1 : 0);
00569                 smp.m16Bit = (UINT8)((xmSample.mType & XMFORMAT_SAMPLE_16BIT) ? 1 : 0);
00570                 smp.mLoopStart = xmSample.mLoopStart;
00571                 smp.mLoopEnd = xmSample.mLoopStart + xmSample.mLoopLength - 1;
00572 
00573                 if (smp.mLoopStart == smp.mLoopEnd)
00574                 {
00575                     smp.mLoopPingpong = 0;
00576                     smp.mLoopForward = 0;
00577                 }
00578 
00579                 smp.mRelativeNote = xmSample.mRelativeNote;
00580                 smp.mFinetune = xmSample.mFinetune;
00581             }
00582 
00583             // Read samples
00584             for (j = 0; j < xmInstrumentHeader.mNbSamples; j++)
00585             {
00586                 XFuXMSample &smp = ins.mSamples[j];
00587 
00588                 if (smp.mSize > 0)
00589                 {
00590                     smp.mOffset = new INT8[smp.mSize];
00591                     memset((INT8 *)smp.mOffset, 0, smp.mSize * sizeof(INT8));
00592 
00593                     if (smp.mOffset == NULL)
00594                     {
00595                         DebugPrint(aTextout, "! Memory allocation for sample "
00596                                    "%02X in instrument %02X failed \n", j, i);
00597                         return 1;
00598                     }
00599 
00600                     DebugPrint(aTextout, "Reading sample \n");
00601                     f->read((INT8 *)smp.mOffset, smp.mSize, 1);
00602 
00603                     if (smp.m16Bit)
00604                     {
00605                         INT16 os, ns;
00606                         INT16 *temp = (INT16 *)smp.mOffset;
00607                         os = 0;
00608 
00609                         smp.mSize >>= 1;
00610                         smp.mLoopStart >>= 1;
00611                         smp.mLoopEnd >>= 1;
00612 
00613                         if (mFlags & XFCAUDIO_16BIT)
00614                         {
00615                             UINT32 a;
00616                             for (a = 0; a < smp.mSize; ++a)
00617                             {
00618                                 ns = (INT16)(os + *(temp + a));
00619                                 *((INT16 *)smp.mOffset + a) = ns;
00620                                 os = ns;
00621                             }
00622                         }
00623                         else
00624                         {
00625                             UINT32 a;
00626                             for (a = 0; a < smp.mSize; ++a)
00627                             {
00628                                 ns = (INT16)(os + *(temp + a));
00629                                 *((INT8 *)smp.mOffset + a) = (INT8)(ns >> 8);
00630                                 os = ns;
00631                             }
00632                             
00633                             smp.m16Bit = 0;
00634 
00635                             INT8 *temp = new INT8[smp.mSize];
00636                             memcpy(temp, smp.mOffset, smp.mSize);
00637                             delete[] (INT8 *)smp.mOffset;
00638                             smp.mOffset = temp;
00639                         }
00640                     }
00641                     else
00642                     {
00643                         INT8 os, ns;
00644                         os = 0;
00645                         UINT32 a;
00646                         for (a = 0; a < smp.mSize; a++)
00647                         {
00648                             ns = (INT8)(os + *((INT8 *)smp.mOffset + a));
00649                             *((INT8 *)smp.mOffset + a) = ns;
00650                             os = ns;
00651                         }
00652                     }
00653                 }
00654             }
00655         
00656             ins.mVolumeFadeout = REALf(xmInstrument.mVolumeFadeout / 65536.0f);
00657 
00658             if (xmInstrument.mVibratoRate) 
00659                 ins.mIsVibrato = 1;
00660             else
00661                 ins.mIsVibrato = 0;
00662 
00663             ins.mVibratoType = xmInstrument.mVibratoType;
00664             ins.mVibratoSweep = xmInstrument.mVibratoSweep;
00665             ins.mVibratoDepth = xmInstrument.mVibratoDepth;
00666             ins.mVibratoRate = xmInstrument.mVibratoRate;
00667 
00668             DebugPrint(aTextout, "sampleheader size: %d \n", xmInstrument.mSampleHeaderSize);
00669 
00670             DebugPrint(aTextout, "keyboard: ");
00671 
00672             for (ii = 0; ii < 96; ii++)
00673             {
00674                 DebugPrint(aTextout, "%d, ", xmInstrument.mKeyboard[ii]);
00675                 if (((ii + 1) % 20) == 0)
00676                     DebugPrint(aTextout, "\n    ");
00677             }
00678 
00679             memcpy(ins.mKeyboard, xmInstrument.mKeyboard, 96);
00680 
00681             DebugPrint(aTextout, "\n");
00682             DebugPrint(aTextout, "volume. envelope: ");
00683 
00684 //            if (xmInstrument.mVolEnvType & ENV_LOOP)
00685 //                xmInstrument.mNbVolEnvPoints =
00686 //                    xmInstrument.mVolEnvLoopEnd + 1;
00687 
00688             for (ii = 0; ii < xmInstrument.mNbVolEnvPoints * 2; ii++)
00689             {
00690                 DebugPrint(aTextout, "%d, ", xmInstrument.mVolumeEnvelope[ii]);
00691 
00692                 if (((ii + 1) % 20) == 0)
00693                     DebugPrint(aTextout, "\n    ");
00694             }
00695 
00696             DebugPrint(aTextout, "\n");
00697             DebugPrint(aTextout, "pan. envelope: ");
00698 
00699 //            if (xmInstrument.mPanEnvType & ENV_LOOP)
00700 //                xmInstrument.mNbPanEnvPoints =
00701 //                    xmInstrument.mPanEnvLoopEnd + 1;
00702 
00703             for (ii = 0; ii < xmInstrument.mNbPanEnvPoints * 2; ii++)
00704             {
00705                 DebugPrint(aTextout, "%d, ", xmInstrument.mPanningEnvelope[ii]);
00706 
00707                 if (((ii + 1) % 20) == 0)
00708                     DebugPrint(aTextout, "\n    ");
00709             }
00710 
00711             // Volume envelope
00712             ins.mVolEnvType = xmInstrument.mVolEnvType;
00713 
00714             if (xmInstrument.mVolEnvLoopStart != xmInstrument.mVolEnvLoopEnd)
00715             {
00716                 ins.mVolEnvLoopStart = xmInstrument.mVolumeEnvelope[
00717                     xmInstrument.mVolEnvLoopStart * 2];
00718                 ins.mVolEnvLoopEnd = xmInstrument.mVolumeEnvelope[
00719                     xmInstrument.mVolEnvLoopEnd * 2];
00720             }
00721             memset(ins.mVolumeEnvelope, 0, XMFORMAT_SIZEOF_ENVELOPE);
00722 
00723             if (xmInstrument.mNbVolEnvPoints == 1)
00724             {
00725                 // Volume envelope fix for trackers that don't follow FT2 standard
00726                 ins.mVolumeEnvelope[0] = REALf(xmInstrument.mVolumeEnvelope[1] / 64.0f);
00727             }
00728             else
00729             {
00730                 for (ii = 0; ii < xmInstrument.mNbVolEnvPoints - 1; ii++)
00731                 {
00732                     x1 = xmInstrument.mVolumeEnvelope[(ii * 2)];
00733                     y1 = xmInstrument.mVolumeEnvelope[(ii * 2) + 1];
00734                     x2 = xmInstrument.mVolumeEnvelope[((ii + 1) * 2)];
00735                     y2 = xmInstrument.mVolumeEnvelope[((ii + 1) * 2) + 1];
00736 
00737                     dx = (y2 - y1) / (x2 - x1);
00738 
00739                     for (xx = x1; xx <= x2; xx++)
00740                     {
00741                         ins.mVolumeEnvelope[xx] = REALf(y1 / 64.0f);
00742                         y1 += dx;
00743                     }
00744                 }
00745             }
00746 
00747             if (xmInstrument.mVolEnvType & ENV_SUSTAIN)
00748                 ins.mVolEnvSustain = xmInstrument.mVolumeEnvelope[
00749                     xmInstrument.mVolEnvSustain * 2];
00750 
00751             if (xmInstrument.mNbVolEnvPoints > 0)
00752                 ins.mVolEnvEnd = xmInstrument.mVolumeEnvelope[
00753                     (xmInstrument.mNbVolEnvPoints - 1) * 2];
00754 
00755             // Panning envelope
00756             ins.mPanEnvType = xmInstrument.mPanEnvType;
00757 
00758             if (xmInstrument.mPanEnvLoopStart != xmInstrument.mPanEnvLoopEnd)
00759             {
00760                 ins.mPanEnvLoopStart = xmInstrument.mPanningEnvelope[
00761                     xmInstrument.mPanEnvLoopStart * 2];
00762                 ins.mPanEnvLoopEnd = xmInstrument.mPanningEnvelope[
00763                     xmInstrument.mPanEnvLoopEnd * 2];
00764             }
00765             memset(ins.mPanningEnvelope, 0, XMFORMAT_SIZEOF_ENVELOPE);
00766 
00767             if (xmInstrument.mNbPanEnvPoints == 1)
00768             {
00769                 // Panning envelope fix for trackers that don't follow FT2 standard
00770                 ins.mPanningEnvelope[0] = (UINT8)xmInstrument.mPanningEnvelope[1];
00771             }
00772             else
00773             {
00774                 for (ii = 0; ii < xmInstrument.mNbPanEnvPoints - 1; ii++)
00775                 {
00776                     x1 = xmInstrument.mPanningEnvelope[(ii * 2)];
00777                     y1 = xmInstrument.mPanningEnvelope[(ii * 2) + 1];
00778                     x2 = xmInstrument.mPanningEnvelope[((ii + 1) * 2)];
00779                     y2 = xmInstrument.mPanningEnvelope[((ii + 1) * 2) + 1];
00780 
00781                     dx = (y2 - y1) / (x2 - x1);
00782 
00783                     for (xx = x1; xx < x2; xx++)
00784                     {
00785                         ins.mPanningEnvelope[xx] = (UINT8)((INT8)y1);
00786                         y1 += dx;
00787                     }
00788                 }
00789             }
00790 
00791             ins.mPanEnvSustain = xmInstrument.mPanningEnvelope[
00792                 xmInstrument.mPanEnvSustain * 2];
00793 
00794             if (xmInstrument.mNbPanEnvPoints > 0)
00795                 ins.mPanEnvEnd = xmInstrument.mPanningEnvelope[
00796                     (xmInstrument.mNbPanEnvPoints - 1) * 2];
00797         
00798             DebugPrint(aTextout, "\n");
00799 
00800             DebugPrint(aTextout, "nof volpoints %d\n",
00801                        xmInstrument.mNbVolEnvPoints);
00802             DebugPrint(aTextout, "nof panpoints %d\n",
00803                        xmInstrument.mNbPanEnvPoints);
00804             DebugPrint(aTextout, "volume. sustain %d\n",
00805                        xmInstrument.mVolEnvSustain);
00806             DebugPrint(aTextout, "volume. loop start %d\n",
00807                        xmInstrument.mVolEnvLoopStart);
00808             DebugPrint(aTextout, "volume. loop end %d\n",
00809                        xmInstrument.mVolEnvLoopEnd);
00810             DebugPrint(aTextout, "pan. sustain %d\n",
00811                        xmInstrument.mPanEnvSustain);
00812             DebugPrint(aTextout, "pan. loop start %d\n",
00813                        xmInstrument.mPanEnvLoopStart);
00814             DebugPrint(aTextout, "pan. loop end %d\n",
00815                        xmInstrument.mPanEnvLoopEnd);
00816             DebugPrint(aTextout, "volume. type %d\n", xmInstrument.mVolEnvType);
00817             DebugPrint(aTextout, "  env. on? %d\n",
00818                        (xmInstrument.mVolEnvType & ENV_ON) ? 1 : 0);
00819             DebugPrint(aTextout, "  env. sustain? %d\n",
00820                        (xmInstrument.mVolEnvType & ENV_SUSTAIN) ? 1 : 0);
00821             DebugPrint(aTextout, "  env. loop? %d \n",
00822                        (xmInstrument.mVolEnvType & ENV_LOOP) ? 1 : 0);
00823             DebugPrint(aTextout, "pan. type %d\n",
00824                        xmInstrument.mPanEnvType);
00825 
00826             DebugPrint(aTextout, "  env. on? %d\n",
00827                        (xmInstrument.mPanEnvType & ENV_ON) ? 1 : 0);
00828             DebugPrint(aTextout, "  env. sustain? %d\n",
00829                        (xmInstrument.mPanEnvType & ENV_SUSTAIN) ? 1 : 0);
00830             DebugPrint(aTextout, "  env. loop? %d \n",
00831                        (xmInstrument.mPanEnvType & ENV_LOOP) ? 1 : 0);
00832             
00833             DebugPrint(aTextout, "vibr. type %d \n",
00834                        xmInstrument.mVibratoType);
00835             DebugPrint(aTextout, "vibr. sweep %d \n",
00836                        xmInstrument.mVibratoSweep);
00837             DebugPrint(aTextout, "vibr. depth %d \n",
00838                        xmInstrument.mVibratoDepth);
00839             DebugPrint(aTextout, "vibr. rate %d \n",
00840                        xmInstrument.mVibratoRate);
00841             DebugPrint(aTextout, "volume. fadeout %d \n\n",
00842                        xmInstrument.mVolumeFadeout);
00843         }
00844         else
00845         {
00846             f->seek(skip, SEEK_CUR);
00847         }
00848 
00849         DebugPrint(aTextout, "-----\n\n");
00850     }
00851 
00852     mSong.mNbInstruments = mXMHeader.mNbInstruments;
00853 
00854     DebugPrint(aTextout, "XM read. \n");
00855     DebugPrint(aTextout, "Not changing pattern structure yet.. \n");
00856 
00857     f->close();
00858 
00859     return 0;
00860 }
00861 
00862 
00863 UINT32 XFuXMPlayer::getPeriod(INT8 aNote, INT8 aFinetune)
00864 {
00865     if (aNote < 0) aNote = 0;
00866     if (aNote > 96) aNote = 96;
00867 
00868     return (7680 - (aNote << 6) - (aFinetune >> 1));
00869 }
00870 
00871 
00872 UINT32 XFuXMPlayer::getSpeed(UINT32 aPeriod, FLOAT32 aSamplingRate)
00873 {
00874     INT32 freq;
00875     INT32 shift = (INT32)(aPeriod / 768);
00876     
00877     if (shift >= 0)
00878         freq = linearFrequencyTable[aPeriod - (shift << 9) - (shift << 8)] >> shift;
00879     //return linearFrequencyTable[aPeriod % 768] >> shift;
00880     else
00881         freq = linearFrequencyTable[aPeriod - (shift << 9) - (shift << 8)] << (-shift);
00882     //return linearFrequencyTable[aPeriod % 768] << (-shift);
00883     
00884 /*
00885     FLOAT32 freq = (FLOAT32)(8363.0f * pow(2.0f, (4608.f - (FLOAT32)period) / 768.0f));
00886 */
00887     
00888     return (INT32)((freq / aSamplingRate) * FP_VALUE);
00889 }
00890 
00891 
00892 XFuXMFormatAtom XFuXMPlayer::getAtom()
00893 {
00894     UINT8 *XMFORMAT_pa = mPatternData[mPatternNb].mData;
00895     XFuXMFormatAtom ta;
00896     char b;
00897     ta.mNote = 0;
00898     ta.mVolume = 0;
00899     ta.mInstrumentNb = 0;
00900     ta.mEffectType = 0;
00901     ta.mEffectValue = 0;
00902 
00903     b = *(XMFORMAT_pa + mPpoint++);
00904     if ((b & 128) == 128)
00905     {
00906         // Packed atom
00907         if ((b & 1) == 1)
00908             ta.mNote = *(XMFORMAT_pa + mPpoint++);
00909         if ((b & 2) == 2)
00910             ta.mInstrumentNb = *(XMFORMAT_pa + mPpoint++);
00911         if ((b & 4) == 4)
00912             ta.mVolume = *(XMFORMAT_pa + mPpoint++);
00913         if ((b & 8) == 8)
00914             ta.mEffectType = *(XMFORMAT_pa + mPpoint++);
00915         if ((b & 16) == 16)
00916             ta.mEffectValue = *(XMFORMAT_pa + mPpoint++);
00917     }
00918     else
00919     {
00920         // Normal atom
00921         ta.mNote = b;
00922         ta.mInstrumentNb = *(XMFORMAT_pa + mPpoint++);
00923         ta.mVolume = *(XMFORMAT_pa + mPpoint++);
00924         ta.mEffectType = *(XMFORMAT_pa + mPpoint++);
00925         ta.mEffectValue = *(XMFORMAT_pa + mPpoint++);
00926     }
00927 
00928     return ta;
00929 }
00930 
00931 
00932 void XFuXMPlayer::initChannel(XFuXMChannel &aCh)
00933 {
00934     aCh.mIsValid = 1;
00935     aCh.mInitSample = 0;
00936 
00937     // Initialize sample if valid note
00938     if ((aCh.mTa.mNote > 0) && (aCh.mTa.mNote < 97))
00939     {
00940         aCh.mNote = (INT8)(aCh.mTa.mNote - 1);
00941         aCh.mInitSample = 1;
00942 
00943         aCh.mTremorTicker = 0;
00944         aCh.mMultiRetrigTicker = 0;        
00945     }
00946     else if (aCh.mTa.mNote != 0)
00947         aCh.mIsValid = 0;
00948 
00949     aCh.mVolumeColumn = aCh.mTa.mVolume;
00950 
00951     if (aCh.mTa.mInstrumentNb != 0)
00952     {
00953         // New instrument
00954         aCh.mInstrumentNb = (INT16)(aCh.mTa.mInstrumentNb - 1);
00955 
00956         if (aCh.mInstrumentNb < mSong.mNbInstruments)
00957         {
00958             aCh.mCurrentInstrument = mInstruments[aCh.mInstrumentNb];
00959 
00960             if (aCh.mCurrentInstrument.mKeyboard[aCh.mNote] < aCh.mCurrentInstrument.mNbSamples)
00961             {
00962                 if (aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]].mOffset != NULL)
00963                 {
00964                     aCh.mCurrentSample = aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]];
00965                 }
00966                 else aCh.mIsValid = 0;
00967             }
00968             else aCh.mIsValid = 0;
00969         }
00970         else aCh.mIsValid = 0;
00971         
00972         aCh.mVolume = aCh.mCurrentSample.mVolume;
00973         aCh.mBaseVolume = aCh.mVolume;
00974 
00975         aCh.mPan = aCh.mCurrentSample.mPan;
00976     }
00977     else
00978     {
00979         if ((aCh.mInstrumentNb != -1) && (aCh.mInstrumentNb < mSong.mNbInstruments))
00980         {            
00981             aCh.mCurrentInstrument = mInstruments[aCh.mInstrumentNb];
00982 
00983             if (aCh.mCurrentInstrument.mKeyboard[aCh.mNote] < aCh.mCurrentInstrument.mNbSamples)
00984             {
00985                 if (aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]].mOffset != NULL)
00986                 {
00987                     aCh.mCurrentSample = aCh.mCurrentInstrument.mSamples[aCh.mCurrentInstrument.mKeyboard[aCh.mNote]];
00988                 }
00989                 else aCh.mIsValid = 0;
00990             }
00991             else aCh.mIsValid = 0;
00992         }
00993         else aCh.mIsValid = 0;
00994     }
00995 
00996     aCh.mOldPeriod = aCh.mPeriod;
00997 
00998     // Do not initialize sound if note delay or pattern delay effect on
00999     if ((aCh.mInitSample) || (mPatternDelayCounter != 0))
01000         initSound(aCh);
01001 }
01002 
01003 
01004 void XFuXMPlayer::initSound(XFuXMChannel &aCh)
01005 {
01006     if (aCh.mIsValid)
01007     {
01008         // Initialize sample
01009         if (aCh.mInitSample) aCh.mIsSample = 1;
01010 
01011         // New note
01012         aCh.mDirection = 1;
01013 
01014         // Init vibrato
01015         /* Instrument vibrato is independent
01016         aCh.mIsVibrato = aCh.mCurrentInstrument.mIsVibrato;
01017         if (aCh.mCurrentInstrument.mVibratoDepth != 0)
01018             aCh.mVibratoDepth = aCh.mCurrentInstrument.mVibratoDepth;
01019         if (aCh.mCurrentInstrument.mVibratoRate != 0)
01020             aCh.mVibratoRate = aCh.mCurrentInstrument.mVibratoRate;
01021         */
01022         aCh.mIsVibrato = 0;
01023 
01024         if ((aCh.mVibratoWaveform & WAVEFORM_NO_RETRIG) == 0) aCh.mVibratoPointer = 0;
01025         if ((aCh.mTremoloWaveform & WAVEFORM_NO_RETRIG) == 0) aCh.mTremoloPointer = 0;
01026 
01027         // Init volume envelope
01028         aCh.mVolEnvType = aCh.mCurrentInstrument.mVolEnvType;
01029         aCh.mVolEnvPointer = 0;
01030         aCh.mVolEnvSpeed = 1;
01031         aCh.mVolEnvLoopStart = aCh.mCurrentInstrument.mVolEnvLoopStart;
01032         aCh.mVolEnvLoopEnd = aCh.mCurrentInstrument.mVolEnvLoopEnd;
01033         aCh.mVolEnvSustain = aCh.mCurrentInstrument.mVolEnvSustain;
01034 
01035         aCh.mVolumeFadeout = aCh.mCurrentInstrument.mVolumeFadeout;
01036         aCh.mVolumeFadeoutValue = REAL(1);
01037 
01038         // Init panning envelope
01039         aCh.mPanEnvType = aCh.mCurrentInstrument.mPanEnvType;
01040         aCh.mPanEnvPointer = 0;
01041         aCh.mPanEnvSpeed = 1;
01042         aCh.mPanEnvLoopStart = aCh.mCurrentInstrument.mPanEnvLoopStart;
01043         aCh.mPanEnvLoopEnd = aCh.mCurrentInstrument.mPanEnvLoopEnd;
01044         aCh.mPanEnvSustain = aCh.mCurrentInstrument.mPanEnvSustain;
01045 
01046         aCh.mSustainReleased = 0;
01047 
01048         aCh.mOffset = aCh.mCurrentSample.mOffset;
01049         aCh.mFinetune = aCh.mCurrentSample.mFinetune;
01050 
01051         if ((aCh.mEffectType != 0x3) &&   // No tone portamento
01052             (aCh.mEffectType != 0x5) &&   // No tone portamento + volume slide
01053             (aCh.mVolumeColumn < 0xF0)) // No volume column tone portamento
01054             aCh.mPointer = 0; // Reset pointer if no tone effect
01055 
01056         aCh.mLength = (aCh.mCurrentSample.mSize << FP_BITS);
01057         aCh.mPeriod = getPeriod((INT8)(aCh.mNote + aCh.mCurrentSample.mRelativeNote), aCh.mFinetune);
01058         aCh.mBasePeriod = aCh.mPeriod;
01059 
01060         aCh.mLoop = 0;
01061         if (aCh.mCurrentSample.mLoopForward) aCh.mLoop = LOOP_FORWARD;
01062         if (aCh.mCurrentSample.mLoopPingpong) aCh.mLoop = LOOP_PINGPONG;
01063         aCh.mLoopStart = (aCh.mCurrentSample.mLoopStart << FP_BITS);
01064         aCh.mLoopEnd = (aCh.mCurrentSample.mLoopEnd << FP_BITS);
01065     }
01066     else
01067         aCh.mIsSample = 0;
01068 }
01069 
01070 
01071 void XFuXMPlayer::notifyHandlers(XFuXMChannel &aCh)
01072 {
01073     XFuXMPlayerEvent event;
01074 
01075     event.mNote = aCh.mNote;
01076     event.mInstrumentNb = aCh.mInstrumentNb;
01077     event.mVolume = aCh.mVolume;
01078 
01079     if ((aCh.mEffectType != 0xE) && (aCh.mEffectType != 0x21))
01080     {
01081         event.mEffectType = aCh.mEffectType;
01082         event.mEffectValue = aCh.mEffectValue;
01083     }
01084     else
01085     {
01086         event.mEffectType = (INT16)((aCh.mEffectType << 4) | (aCh.mEffectValue >> 4));
01087         event.mEffectValue = (INT16)(aCh.mEffectValue & 0xF);
01088     }
01089 
01090     event.mPlayer = this;
01091 
01092     XFcLinkedList<XFuXMPlayerEventHandlerSlot>::forwardIterator i;
01093     XFuXMPlayerEventHandlerSlot temp;
01094 
01095     for (i = mEventHandlers->forwardBegin(); i != mEventHandlers->forwardEnd(); ++i)
01096     {
01097         temp = i.getData();
01098 
01099         if (((temp.mEvent.mNote != -1) && (temp.mEvent.mNote == event.mNote)) ||
01100             ((temp.mEvent.mInstrumentNb != -1) && (temp.mEvent.mInstrumentNb == event.mInstrumentNb)) ||
01101             ((temp.mEvent.mEffectType != -1) && (temp.mEvent.mEffectType == event.mEffectType)))
01102         {
01103             temp.mHandler->handleXMPlayerEvent(event);
01104         }
01105     }
01106 }
01107 
01108 
01109 void XFuXMPlayer::initSong(INT16 aStartOrder)
01110 {
01111     INT i;
01112 
01113     if ((aStartOrder < 0) || (aStartOrder >= mSong.mSongLength)) aStartOrder = 0;
01114     mCurrentOrder = (INT16)(aStartOrder - 1);
01115 
01116     mPatternNb = mSong.mOrderTable[aStartOrder];
01117     if (mPatternNb >= mSong.mNbPatterns) mPatternNb = mSong.mOrderTable[0];
01118 
01119     mCurrentRow = 1024;
01120 
01121     mPatternDelayCounter = 0;
01122     mPatternDelayCounterTemp = 0;
01123     mJumpFlag = 0;
01124     mIsRead = 1;
01125 
01126     mTickRate = (2.0f * mSong.mBpm / 5.0f);
01127 
01128     mSamplesPerTick = (INT32)(mSampleRate / mTickRate);
01129 
01130     mCurrentTick = (UINT8)(mSong.mTempo - 1); // Playing starts from last tick
01131     mSamplePointer = mSamplesPerTick - 1; // Playing starts from last sample of last tick
01132 
01133     mTotalTicks = 0;
01134 
01135     mSong.mGlobalVolume = 64;
01136 
01137     for (i = 0; i < mSong.mNbChannels; i++)
01138     {
01139         XFuXMChannel &ch = mChannels[i];
01140 
01141         ch.mOffset = NULL;
01142         ch.mPointer = 0;
01143         ch.mLength = 0;
01144         ch.mInstrumentNb = -1;
01145         ch.mSpeed = 0;
01146         ch.mPeriod = 0;
01147 
01148         ch.mLoop = 0;
01149         ch.mLoopStart = 0;
01150         ch.mLoopEnd = 0;
01151 
01152         ch.mIsSample = 0;
01153 
01154         ch.mVolume = 0;
01155         ch.mBaseVolume = 0;
01156         ch.mFinalOldVolume = 0;
01157         ch.mFinalVolumeSpeed = 0;
01158 
01159         ch.mNote = 0;
01160 
01161         ch.mDirection = 1;
01162 
01163         ch.mVolEnvType = 0;
01164         ch.mVolEnvPointer = 0;
01165         ch.mVolEnvSpeed = 0;
01166         ch.mVolEnvLoopStart = 0;
01167         ch.mVolEnvLoopEnd = 0;
01168         ch.mVolEnvSustain = 0;
01169         ch.mVolEnvValue = 0;
01170 
01171         ch.mPanEnvType = 0;
01172         ch.mPanEnvPointer = 0;
01173         ch.mPanEnvSpeed = 0;
01174         ch.mPanEnvLoopStart = 0;
01175         ch.mPanEnvLoopEnd = 0;
01176         ch.mPanEnvSustain = 0;
01177         ch.mPanEnvValue = 0;
01178 
01179         ch.mVolumeFadeout = 0;
01180         ch.mVolumeFadeoutValue = 0;
01181 
01182         ch.mSustainReleased = 0;
01183 
01184         ch.mVolumeColumn = 0;
01185 
01186         ch.mEffectType = 0;
01187         ch.mEffectValue = 0;
01188         ch.mTonePortamentoV = 0;
01189         ch.mVolumeSlideV = 0;
01190         ch.mGlobalVolumeSlideV = 0;
01191         ch.mFineVolumeSlideUpV = 0;
01192         ch.mFineVolumeSlideDownV = 0;
01193         ch.mFinePortamentoUpV = 0;
01194         ch.mFinePortamentoDownV = 0;
01195         ch.mFineVolumeSlideUpV = 0;
01196         ch.mFineVolumeSlideDownV = 0;
01197         ch.mGlobalVolumeSlideV = 0;
01198         ch.mMultiRetrigVolumeV = 0;
01199         ch.mMultiRetrigRateV = 0;
01200         ch.mTremorV = 0;
01201         ch.mExtraFinePortamentoUpV = 0;
01202         ch.mExtraFinePortamentoDownV = 0;
01203 
01204         ch.mMultiRetrigTicker = 0;
01205         ch.mTremorTicker = 0;
01206 
01207         ch.mPeriod = 0;
01208         ch.mBasePeriod = 0;
01209         ch.mOldPeriod = 0;
01210         ch.mDestPeriod = 0;
01211 
01212         ch.mIsVibrato = 0;
01213         ch.mVibratoDepth = 0;
01214         ch.mVibratoRate = 0;
01215         ch.mVibratoPointer = 0;
01216         ch.mVibratoWaveform = WAVEFORM_SINEWAVE;
01217 
01218         ch.mTremoloDepth = 0;
01219         ch.mTremoloRate = 0;
01220         ch.mTremoloPointer = 0;
01221         ch.mTremoloWaveform = WAVEFORM_SINEWAVE;
01222     }
01223 }
01224 
01225 
01226 INT32 XFuXMPlayer::getTick()
01227 {
01228     return (INT32)((mTotalTicks * 1000) / mSampleRate);
01229 }
01230 
01231 
01232 INT16 XFuXMPlayer::getCurrentOrder()
01233 {
01234     return mCurrentOrder;
01235 }
01236 
01237 
01238 void XFuXMPlayer::addHandler(XFuXMPlayerEvent aEvent, XFuXMPlayerEventHandler *aHandler)
01239 {
01240     if (aHandler != NULL)
01241     {
01242         XFuXMPlayerEventHandlerSlot temp;
01243         temp.mEvent = aEvent;
01244         temp.mHandler = aHandler;
01245 
01246         mEventHandlers->addLast(temp);
01247     }
01248 }
01249 
01250 
01251 INT XFuXMPlayer::removeHandler(XFuXMPlayerEventHandler *aHandler)
01252 {
01253     if (aHandler != NULL)
01254     {
01255         XFuXMPlayerEventHandlerSlot temp;
01256         temp.mHandler = aHandler;
01257 
01258         return mEventHandlers->remove(temp);
01259     }
01260 
01261     return 0;
01262 }
01263 
01264 
01265 void XFuXMPlayer::removeHandlers()
01266 {
01267     XFcLinkedList<XFuXMPlayerEventHandlerSlot>::forwardIterator i = mEventHandlers->forwardBegin();
01268     XFuXMPlayerEventHandlerSlot temp;
01269 
01270     while (i.isValid())
01271     {
01272         mEventHandlers->remove(i);
01273     }
01274 }
01275 
01276 
01277 void XFuXMPlayer::stop()
01278 {
01279     initSong(0);
01280 }
01281 
01282 
01283 // For MSVC
01284 #pragma warning(disable:4244)
01285 
01286 UINT32 XFuXMPlayer::stream(void *aBuf, INT32 aSamples)
01287 {
01288     INT32 c = 0;
01289     INT32 cLeft = 0, cRight = 0;
01290 
01291     INT32 chan;
01292 
01293     INT32 index;
01294     INT32 counter;
01295     INT32 indicesLeft;
01296     INT32 ticksLeft;
01297     INT32 samplesToRender;
01298 
01299     INT32 delta;
01300     INT32 val1, val2;
01301     INT32 value;
01302     INT32 temp;
01303 
01304     XFuXMFormatAtom ta;
01305     INT16 *vibratoTable = mSineWaveTable;
01306     INT16 *tremoloTable = mSineWaveTable;
01307 
01308     for (index = 0; index < aSamples; )
01309     {
01310         if (++mSamplePointer == mSamplesPerTick)
01311         {
01312             // Tick finished
01313             mSamplePointer = 0;
01314 
01315             mRamp = 0;
01316 
01317             if (mIsRead && (++mCurrentTick == mSong.mTempo))
01318             {
01319                 // Row finished
01320                 mCurrentTick = 0;
01321 
01322                 if (mPatternDelayCounter == 0) mCurrentRow++;
01323                 else mPatternDelayCounter--;
01324 
01325                 if ((mCurrentRow >= mXMPatternHeaders[mPatternNb].mNbRows) || (mJumpFlag != 0))
01326                 {
01327                     // Pattern finished
01328                     mCurrentOrder++;
01329                     if (mCurrentOrder >= mSong.mSongLength) mCurrentOrder = mSong.mRestartPosition;
01330 
01331                     mPatternNb = mSong.mOrderTable[mCurrentOrder];
01332                     if (mPatternNb >= mSong.mNbPatterns) mPatternNb = mSong.mOrderTable[0];
01333 
01334                     if (mJumpFlag == 0) mCurrentRow = 0;
01335                     mPpoint = mPatternData[mPatternNb].mRows[mCurrentRow];
01336 
01337                     mJumpFlag = 0;
01338                 }
01339 
01340                 for (chan = 0; chan < mSong.mNbChannels; chan++)
01341                 {
01342                     XFuXMChannel &ch = mChannels[chan];
01343 
01344                     if (mPatternDelayCounter == 0)
01345                     {
01346                         ta = getAtom(); // Get track data
01347 
01348                         ch.mTa = ta;
01349 
01350                         ch.mEffectType = ta.mEffectType;
01351                         ch.mEffectValue = ta.mEffectValue;
01352 
01353                         if (!((ch.mEffectType == 0xE) &&
01354                             // No change if note delay effect
01355                             (((ch.mEffectValue >> 4) & 0xF) == 0xD)))
01356                         {
01357                             initChannel(ch);
01358                         }
01359                     }
01360 
01361                     // Volume column effects
01362                     if (ch.mVolumeColumn != 0)
01363                     {
01364                         // Set volume
01365                         if ((ch.mVolumeColumn >= 0x10) && (ch.mVolumeColumn <= 0x50))
01366                         {
01367                             ch.mVolume = (INT8)(ch.mVolumeColumn - 0x10);
01368                             if (ch.mVolume > 0x40) ch.mVolume = 0x40;
01369                             ch.mBaseVolume = ch.mVolume;
01370                         }
01371                         else
01372                         {
01373                             switch (ch.mVolumeColumn >> 4)
01374                             {
01375                             case 0x8:   // Fine volume slide down (arrow down)
01376                                 if (ch.mVolume > 0) ch.mVolume -= (ch.mVolumeColumn & 0xF);
01377                                 ch.mBaseVolume = ch.mVolume;
01378                                 break;
01379 
01380                             case 0x9:    // Fine volume slide up (arrow up)
01381                                 if (ch.mVolume < 0x40) ch.mVolume += (ch.mVolumeColumn & 0xF);
01382                                 ch.mBaseVolume = ch.mVolume;
01383                                 break;
01384 
01385                             case 0xA:   // Set vibrato speed (Sxy)
01386                                 if ((ch.mVolumeColumn & 0xF) != 0) 
01387                                     ch.mVibratoRate = (UINT8)(ch.mVolumeColumn & 0xF);
01388                                 break;
01389 
01390                             case 0xB:   // Set vibrato depth (Vxy)
01391                                 if ((ch.mVolumeColumn & 0xF) != 0)
01392                                 {
01393                                     ch.mVibratoDepth = (UINT8)((ch.mVolumeColumn & 0xF) * 4);
01394                                     ch.mIsVibrato = 1;
01395                                 }
01396                                 break;
01397 
01398                             case 0xC:   // Set panning (Pxy)
01399                                 ch.mPan = (UINT8)((ch.mVolumeColumn & 0xF) << 4);
01400                                 break;
01401 
01402                             case 0xD:   // Panning slide left (left arrow)
01403                                 if (ch.mPan > 0) ch.mPan -= (ch.mVolumeColumn & 0xF);
01404                                 break;
01405 
01406                             case 0xE:   // Panning slide right (right arrow)
01407                                 if (ch.mPan < 0xFF) ch.mPan += (ch.mVolumeColumn & 0xF);
01408                                 break;
01409 
01410                             case 0xF:   // Tone portamento (Mxy)
01411                                 if ((ch.mVolumeColumn & 0xF) != 0)
01412                                     ch.mTonePortamentoV = (UINT8)((ch.mVolumeColumn & 0xF) << 4);
01413                         
01414                                 if ((ch.mTa.mNote != 0) && (ch.mTa.mNote != 97))
01415                                 {
01416                                     ch.mDestPeriod = ch.mPeriod;
01417                                     ch.mPeriod = ch.mOldPeriod;
01418                                 }
01419                                 break;
01420                             }
01421                         }
01422                     }
01423 
01424                     // Row effects
01425                     switch (ch.mEffectType)
01426                     {
01427                         case 0x0:   // Arpeggio (0xy)
01428                             if (ch.mEffectValue != 0) ch.mPeriod = ch.mBasePeriod;
01429                             break;
01430 
01431                         case 0x1:   // Portamento up (1xy)
01432                             if (ch.mEffectValue != 0) ch.mPortamentoUpV = ch.mEffectValue;
01433                             break;
01434 
01435                         case 0x2:   // Portamento down (2xy)
01436                             if (ch.mEffectValue != 0) ch.mPortamentoDownV = ch.mEffectValue;
01437                             break;
01438 
01439                         case 0x3:   // Tone portamento (3xy)
01440                             if (ch.mOldPeriod != 0)
01441                             {
01442                                 if (ch.mEffectValue != 0) ch.mTonePortamentoV = ch.mEffectValue;
01443 
01444                                 if ((ch.mTa.mNote != 0) && (ch.mTa.mNote != 97))
01445                                 {
01446                                     ch.mDestPeriod = ch.mPeriod;
01447                                     ch.mPeriod = ch.mOldPeriod;
01448                                     ch.mBasePeriod = ch.mPeriod;
01449                                 }
01450                             }
01451                             break;
01452                     
01453                         case 0x4:   // Vibrato (4xy)
01454                             if ((ch.mEffectValue & 0xF) != 0)
01455                                 ch.mVibratoDepth = (UINT8)((ch.mEffectValue & 0xF) * 4);
01456 
01457                             if ((ch.mEffectValue >> 4) != 0)
01458                                 ch.mVibratoRate = (UINT8)(ch.mEffectValue >> 4);
01459 
01460                             ch.mIsVibrato = 1;
01461                             break;
01462                     
01463                         case 0x5:   // Tone portamento + volume slide (5xy)
01464                             if (ch.mEffectValue != 0) ch.mVolumeSlideV = ch.mEffectValue;
01465                             break;
01466 
01467                         case 0x6:   // Vibrato + volume slide (6xy)
01468                             if (ch.mEffectValue != 0) ch.mVolumeSlideV = ch.mEffectValue;
01469 
01470                             ch.mIsVibrato = 1;
01471                             break;
01472 
01473                         case 0x7:   // Tremolo (7xy)
01474                             if ((ch.mEffectValue & 0xF) != 0)
01475                                 ch.mTremoloDepth = (UINT8)(ch.mEffectValue & 0xF);
01476 
01477                             if ((ch.mEffectValue >> 4) != 0)
01478                                 ch.mTremoloRate = (UINT8)(ch.mEffectValue >> 4);
01479                             break;
01480 
01481                         case 0x8:   // Set panning (8xy)
01482                             ch.mPan = ch.mEffectValue;
01483                             break;
01484 
01485                         case 0x9:   // Sample offset (9xy)
01486                             ch.mPointer = ch.mEffectValue << (8 + FP_BITS);
01487                             XFCASSERT(ch.mPointer < ch.mLength);
01488                             // FastTracker2 behaviour when not in debug mode,
01489                             // if offset is beyond sample length, stop sample
01490                             if (ch.mPointer >= ch.mLength) ch.mIsSample = 0;
01491                             break;
01492 
01493                         case 0xA:   // Volume slide (Axy)
01494                             if (ch.mEffectValue != 0) ch.mVolumeSlideV = ch.mEffectValue;
01495                             break;
01496 
01497                         case 0xB:   // Jump to pattern (Bxy)
01498                             if (mJumpFlag == 0)
01499                             {
01500                                 mCurrentRow = -1;
01501                                 mCurrentOrder = (INT16)(ch.mEffectValue - 1);
01502                                 mJumpFlag = 1;
01503                             }
01504                             break;
01505 
01506                         case 0xC:   // Volume (Cxy)
01507                             ch.mVolume = ch.mEffectValue;
01508                             if (ch.mVolume > 0x40) ch.mVolume = 0x40;
01509                             ch.mBaseVolume = ch.mVolume;
01510                             break;
01511                     
01512                         case 0xD:   // Pattern break (Dxy)
01513                             if (mJumpFlag == 0)
01514                             {
01515                                 mCurrentRow = (INT16)(ch.mEffectValue - 1);
01516                                 mJumpFlag = 1;
01517                             }
01518                             break;
01519 
01520                         case 0xE:   // Extra effects (Exy)
01521                             switch ((ch.mEffectValue >> 4))
01522                             {
01523                                 case 0x1:   // Fine portamento up (E1y)
01524                                     if ((ch.mEffectValue & 0xF) != 0)
01525                                         ch.mFinePortamentoUpV = (UINT8)(ch.mEffectValue & 0xF);
01526 
01527                                     ch.mPeriod -= ch.mFinePortamentoUpV * 4;
01528                                     ch.mBasePeriod = ch.mPeriod;
01529                                     break;
01530 
01531                                 case 0x2:   // Fine portamento down (E2y)
01532                                     if ((ch.mEffectValue & 0xF) != 0)
01533                                         ch.mFinePortamentoUpV = (UINT8)(ch.mEffectValue & 0xF);
01534 
01535                                     ch.mPeriod += ch.mFinePortamentoUpV * 4;
01536                                     ch.mBasePeriod = ch.mPeriod;
01537                                     break;
01538 
01539                                 case 0x3:   // Glissando control (E3y), FIX ME!
01540                                     break;
01541 
01542                                 case 0x4:   // Vibrato waveform (E4y)
01543                                     if ((ch.mEffectValue & 0xF) < 7)
01544                                         ch.mVibratoWaveform = (UINT8)(ch.mEffectValue & 0xF);
01545                                     break;
01546 
01547                                 case 0x5:   // Set finetune (E5y)
01548                                     ch.mFinetune = (INT8)((ch.mEffectValue & 0xF) << 1);
01549                                     break;
01550 
01551                                 case 0x6:   // Pattern loop (E6y), FIX ME!
01552                                     break;
01553 
01554                                 case 0x7:   // Tremolo waveform (E7y)
01555                                     if ((ch.mEffectValue & 0xF) < 7)
01556                                         ch.mTremoloWaveform = (UINT8)(ch.mEffectValue & 0xF);
01557                                     break;
01558 
01559                                 case 0xA:   // Fine volume slide up (EAy)
01560                                     if ((ch.mEffectValue & 0xF) != 0)
01561                                         ch.mFineVolumeSlideUpV = (UINT8)(ch.mEffectValue & 0xF);
01562 
01563                                     if (ch.mVolume < 0x40) ch.mVolume += ch.mFineVolumeSlideUpV;
01564                                     ch.mBaseVolume = ch.mVolume;
01565                                     break;
01566 
01567                                 case 0xB:   // Fine volume slide down (EBy)
01568                                     if ((ch.mEffectValue & 0xF) != 0)
01569                                         ch.mFineVolumeSlideDownV = (UINT8)(ch.mEffectValue & 0xF);
01570 
01571                                     if (ch.mVolume > 0) ch.mVolume -= ch.mFineVolumeSlideDownV;
01572                                     ch.mBaseVolume = ch.mVolume;
01573                                     break;
01574 
01575                                 case 0xE:   // Pattern delay (EEy)
01576                                     if (mPatternDelayCounter == 0)
01577                                         mPatternDelayCounterTemp = (UINT8)(ch.mEffectValue & 0xF);
01578                                     break;
01579 
01580                                 }
01581                             break;
01582                     
01583                         case 0xF:   // Tempo or BPM change (Fxy)
01584                             if (ch.mEffectValue < 32) 
01585                             {
01586                                 mSong.mTempo = ch.mEffectValue;
01587                                 if (mSong.mTempo == 0) mIsRead = 0;
01588                             }
01589                             else
01590                             { // BPM
01591                                 mSong.mBpm = ch.mEffectValue;
01592                                 mTickRate = 2.0f * mSong.mBpm / 5.0f;
01593 
01594                                 mSamplesPerTick = (INT)(mSampleRate / mTickRate);
01595                             }
01596                             break;
01597 
01598                         case 0x10:  // Global volume (Gxy)
01599                             mSong.mGlobalVolume = ch.mEffectValue;
01600 
01601                             if (mSong.mGlobalVolume > 0x40) mSong.mGlobalVolume = 0x40;
01602                             break;
01603 
01604                         case 0x11:  // Global volume slide (Hxy)
01605                             if (ch.mEffectValue != 0) ch.mGlobalVolumeSlideV = ch.mEffectValue;
01606 
01607                             if (mSong.mGlobalVolume < 0x40) 
01608                                 mSong.mGlobalVolume += (ch.mGlobalVolumeSlideV >> 4) << 1;
01609                             if (mSong.mGlobalVolume > 0) 
01610                                 mSong.mGlobalVolume -= (ch.mGlobalVolumeSlideV & 0xF) << 1;
01611                             break;
01612 
01613                         case 0x15:  // Set envelope position (Lxy), FIX ME!
01614                             break;
01615 
01616                         case 0x19:  // Panning slide (Pxy)
01617                             if (ch.mEffectValue != 0) ch.mPanningSlideV = ch.mEffectValue;
01618                             break;
01619 
01620                         case 0x1B:  // Multi retrig note (Rxy)
01621                             if ((ch.mEffectValue >> 4) != 0)
01622                                 ch.mMultiRetrigVolumeV = (UINT8)(ch.mEffectValue >> 4);
01623 
01624                             if ((ch.mEffectValue & 0xF) != 0)
01625                                 ch.mMultiRetrigRateV = (UINT8)(ch.mEffectValue & 0xF);
01626 
01627                             if (ch.mMultiRetrigRateV != 0)
01628                             {
01629                                 if ((ch.mMultiRetrigTicker % ch.mMultiRetrigRateV) == 0)
01630                                 {
01631                                     ch.mInitSample = 1;
01632                                     initSound(ch);
01633 
01634                                     if ((ch.mMultiRetrigVolumeV != 8) && (ch.mMultiRetrigTicker != 0))
01635                                     {
01636                                         // Don't affect volume on first tick
01637                                         switch (ch.mMultiRetrigVolumeV)
01638                                         {
01639                                             case 0x1:
01640                                                 ch.mVolume -= 1;
01641                                                 break;
01642                                             case 0x2:
01643                                                 ch.mVolume -= 2;
01644                                                 break;
01645                                             case 0x3:
01646                                                 ch.mVolume -= 4;
01647                                                 break;
01648                                             case 0x4:
01649                                                 ch.mVolume -= 8;
01650                                                 break;
01651                                             case 0x5:
01652                                                 ch.mVolume -= 16;
01653                                                 break;
01654                                             case 0x6:
01655                                                 ch.mVolume = (INT8)((ch.mVolume * 2) / 3);
01656                                                 break;
01657                                             case 0x7:
01658                                                 ch.mVolume >>= 1;
01659                                                 break;
01660                                             case 0x9:
01661                                                 ch.mVolume += 1;
01662                                                 break;
01663                                             case 0xA:
01664                                                 ch.mVolume += 2;
01665                                                 break;
01666                                             case 0xB:
01667                                                 ch.mVolume += 4;
01668                                                 break;
01669                                             case 0xC:
01670                                                 ch.mVolume += 8;
01671                                                 break;
01672                                             case 0xD:
01673                                                 ch.mVolume += 16;
01674                                                 break;
01675                                             case 0xE:
01676                                                 ch.mVolume = (INT8)((ch.mVolume * 3) / 2);
01677                                                 break;
01678                                             case 0xF:
01679                                                 ch.mVolume <<= 1;
01680                                                 break;
01681                                         }
01682 
01683                                         ch.mBaseVolume = ch.mVolume;
01684                                     }
01685                                 }
01686                             }
01687 
01688                             ch.mMultiRetrigTicker++;
01689                             break;
01690 
01691                         case 0x1D:  // Tremor (Txy)
01692                             if (ch.mEffectValue != 0) ch.mTremorV = ch.mEffectValue;
01693                         
01694                             if (ch.mTremorV != 0)
01695                             {
01696                                 if ((unsigned char)(ch.mTremorTicker % 
01697                                     ((ch.mTremorV >> 4) + (ch.mTremorV & 0xF) + 2)) < 
01698                                     (ch.mTremorV >> 4) + 1)
01699                                     ch.mVolume = ch.mBaseVolume;
01700                                 else
01701                                     ch.mVolume = 0;
01702                             }
01703                             break;
01704 
01705                         case 0x21:  // Extra fine portamento up/down (X1y/X2y)
01706                             switch(ch.mEffectValue >> 4)
01707                             {
01708                                 case 0x1:   // Extra fine portamento up (X1y)
01709                                     if ((ch.mEffectValue & 0xF) != 0)
01710                                         ch.mExtraFinePortamentoUpV = (UINT8)(ch.mEffectValue & 0xF);
01711 
01712                                     ch.mPeriod -= ch.mExtraFinePortamentoUpV;
01713                                     ch.mBasePeriod = ch.mPeriod;
01714                                     break;
01715                                 case 0x2:   // Extra fine portamento down (X2y)
01716                                     if ((ch.mEffectValue & 0xF) != 0)
01717                                         ch.mExtraFinePortamentoDownV = (UINT8)(ch.mEffectValue & 0xF);
01718 
01719                                     ch.mPeriod -= ch.mExtraFinePortamentoUpV;
01720                                     ch.mBasePeriod = ch.mPeriod;
01721                                     break;
01722                             }
01723                             break;
01724                     }
01725 
01726                     notifyHandlers(ch);
01727 
01728                     // Key off (Kxy)
01729                     if ((ch.mEffectType == 0x14) || (ch.mTa.mNote == 97))
01730                     {
01731                         if (ch.mSustainReleased == 0)
01732                         {
01733                             ch.mSustainReleased = 1;
01734                             if (ch.mVolEnvType & ENV_SUSTAIN)
01735                                 ch.mVolEnvSpeed = 1; // Start envelope
01736 
01737                             if (ch.mVolEnvType == 0)
01738                                 ch.mVolume = 0;
01739 
01740                             // FIX ME!!! PANNING ENVELOPE STUFF MISSING!!!
01741                         }
01742                      }
01743                 }
01744 
01745                 if (mPatternDelayCounterTemp != 0)
01746                 {
01747                     mPatternDelayCounter = mPatternDelayCounterTemp;
01748                     mPatternDelayCounterTemp = 0;
01749                 }
01750             }
01751             else if (mSong.mTempo != 0)
01752             {
01753                 // Tick effects
01754                 for (chan = 0; chan < mSong.mNbChannels; chan++)
01755                 {
01756                     XFuXMChannel &ch = mChannels[chan];
01757 
01758                     if (ch.mVolumeColumn != 0)
01759                     {
01760                         switch(ch.mVolumeColumn >> 4)
01761                         {
01762                         case 0x6:   // Volume slide down (-xy)
01763                             ch.mVolume -= (ch.mVolumeColumn & 0xF);
01764                             ch.mBaseVolume = ch.mVolume;
01765                             break;
01766 
01767                         case 0x7:   // Volume slide up (+xy)
01768                             ch.mVolume += (ch.mVolumeColumn & 0xF);
01769                             ch.mBaseVolume = ch.mVolume;
01770                             break;
01771 
01772                         case 0xF:   // Tone portamento (Mxy)
01773                             if (ch.mOldPeriod != 0)
01774                             {
01775                                 if (ch.mDestPeriod > ch.mPeriod)
01776                                 {
01777                                     ch.mPeriod += (ch.mTonePortamentoV * 4);
01778                                     if (ch.mPeriod > ch.mDestPeriod)
01779                                         ch.mPeriod = ch.mDestPeriod;
01780                                 }
01781                                 else if (ch.mDestPeriod < ch.mPeriod)
01782                                 {
01783                                     ch.mPeriod -= (ch.mTonePortamentoV * 4);
01784                                     if (ch.mPeriod < ch.mDestPeriod)
01785                                         ch.mPeriod = ch.mDestPeriod;
01786                                 }
01787 
01788                                 ch.mBasePeriod = ch.mPeriod;
01789                             }
01790                             break;
01791                         }
01792                     }
01793 
01794                     switch (ch.mEffectType)
01795                     {
01796                         case 0x0:   // Arpeggio (0xy)
01797                             if (ch.mEffectValue != 0)
01798                             {
01799                                 switch (mCurrentTick % 3)
01800                                 {
01801                                     case 0:
01802                                         ch.mPeriod = ch.mBasePeriod;
01803                                         break;
01804                                     case 1:
01805                                         ch.mPeriod = ch.mBasePeriod - (ch.mEffectValue >> 4) * 64;
01806                                         break;
01807                                     case 2:
01808                                         ch.mPeriod = ch.mBasePeriod - (ch.mEffectValue & 0xF) * 64;
01809                                         break;
01810                                 }
01811                             }
01812                             break;
01813 
01814                         case 0x1:   // Portamento up (1xy)
01815                             ch.mPeriod -= (ch.mPortamentoUpV * 4);
01816                             ch.mBasePeriod = ch.mPeriod;
01817                             break;
01818 
01819                         case 0x2:   // Portamento down (2xy)
01820                             ch.mPeriod += (ch.mPortamentoDownV * 4);
01821                             ch.mBasePeriod = ch.mPeriod;
01822                             break;
01823 
01824                         case 0x7:   // Tremolo (7xy), FIX ME!
01825                             if (ch.mTremoloWaveform & WAVEFORM_SINEWAVE)
01826                                 tremoloTable = mSineWaveTable;
01827                             else if (ch.mTremoloWaveform & WAVEFORM_SQUAREWAVE)
01828                                 tremoloTable = mSquareWaveTable;
01829                             else if (ch.mTremoloWaveform & WAVEFORM_RAMPDOWN)
01830                                 tremoloTable = mRampDownTable;
01831                             // FIX ME! Random waveform not supported
01832 
01833                             ch.mVolume = (INT8)(ch.mBaseVolume + 
01834                                 ((tremoloTable[ch.mTremoloPointer] * ch.mTremoloDepth) >> 6));
01835                             ch.mTremoloPointer = (UINT8)(
01836                                 (ch.mTremoloPointer + ch.mTremoloRate) % XMFORMAT_SIZEOF_WAVEFORM);
01837                             break;
01838 
01839                         case 0xE:   // Extra effects (Exy)
01840                             switch ((ch.mEffectValue >> 4))
01841                             {
01842                                 case 0x9:   // Retrig note (E9y)
01843                                     if (((ch.mEffectValue & 0xF) != 0) &&
01844                                         ((mCurrentTick % (ch.mEffectValue & 0xF)) == 0))
01845                                     {
01846                                         ch.mInitSample = 1;
01847                                         initSound(ch);
01848                                     }
01849                                     break;
01850 
01851                                 case 0xC:   // Note cut (ECy)
01852                                     if (mCurrentTick == (ch.mEffectValue & 0xF))
01853                                     {
01854                                         ch.mVolume = 0;
01855                                         ch.mBaseVolume = ch.mVolume;
01856                                     }
01857                                     break;
01858 
01859                                 case 0xD:   // Note delay (EDy)
01860                                     if (mCurrentTick == (ch.mEffectValue & 0xF))
01861                                     {
01862                                         initChannel(ch);
01863                                     }
01864                                     break;
01865                             }
01866                             break;
01867 
01868                         case 0x19:  // Panning slide (Pxy)
01869                             ch.mPan += (ch.mPanningSlideV >> 4);
01870                             if (ch.mPan > 0xFF) ch.mPan = 0xFF;
01871 
01872                             ch.mPan -= (ch.mPanningSlideV & 0xF);
01873                             if (ch.mPan < 0) ch.mPan = 0;
01874 
01875                             break;
01876 
01877                         case 0x1B:  // Multi retrig note (Rxy)
01878                             if (ch.mMultiRetrigRateV != 0)
01879                             {
01880                                 if ((ch.mMultiRetrigTicker % ch.mMultiRetrigRateV) == 0)
01881                                 {
01882                                     ch.mInitSample = 1;
01883                                     initSound(ch);
01884 
01885                                     if ((ch.mMultiRetrigVolumeV != 8) && (ch.mMultiRetrigTicker != 0))
01886                                     {
01887                                         // Don't affect volume on first tick
01888                                         switch (ch.mMultiRetrigVolumeV)
01889                                         {
01890                                             case 0x1:
01891                                                 ch.mVolume -= 1;
01892                                                 break;
01893                                             case 0x2:
01894                                                 ch.mVolume -= 2;
01895                                                 break;
01896                                             case 0x3:
01897                                                 ch.mVolume -= 4;
01898                                                 break;
01899                                             case 0x4:
01900                                                 ch.mVolume -= 8;
01901                                                 break;
01902                                             case 0x5:
01903                                                 ch.mVolume -= 16;
01904                                                 break;
01905                                             case 0x6:
01906                                                 ch.mVolume = (INT8)(ch.mVolume * 2.0f / 3.0f);
01907                                                 break;
01908                                             case 0x7:
01909                                                 ch.mVolume >>= 1;
01910                                                 break;
01911                                             case 0x9:
01912                                                 ch.mVolume += 1;
01913                                                 break;
01914                                             case 0xA:
01915                                                 ch.mVolume += 2;
01916                                                 break;
01917                                             case 0xB:
01918                                                 ch.mVolume += 4;
01919                                                 break;
01920                                             case 0xC:
01921                                                 ch.mVolume += 8;
01922                                                 break;
01923                                             case 0xD:
01924                                                 ch.mVolume += 16;
01925                                                 break;
01926                                             case 0xE:
01927                                                 ch.mVolume = (INT8)(ch.mVolume * 3.0f / 2.0f);
01928                                                 break;
01929                                             case 0xF:
01930                                                 ch.mVolume <<= 1;
01931                                                 break;
01932                                         }
01933 
01934                                         if (ch.mVolume > 0x40) ch.mVolume = 0x40;
01935                                         else if (ch.mVolume < 0) ch.mVolume = 0;
01936 
01937                                         ch.mBaseVolume = ch.mVolume;
01938                                     }
01939                                 }
01940                             }
01941 
01942                             ch.mMultiRetrigTicker++;
01943                             break;
01944 
01945                         case 0x1D:  // Tremor (Txy)
01946                             if (ch.mTremorV != 0)
01947                             {
01948                                 if ((unsigned char)(ch.mTremorTicker % 
01949                                     ((ch.mTremorV >> 4) + (ch.mTremorV & 0xF) + 2)) < 
01950                                     (ch.mTremorV >> 4) + 1)
01951                                     ch.mVolume = ch.mBaseVolume;
01952                                 else
01953                                     ch.mVolume = 0;
01954                             }
01955 
01956                             ch.mTremorTicker++;
01957                             break;
01958 
01959                     }
01960 
01961                     // Tone portamento (3xy) /
01962                     // tone portamento + volume slide (5xy) /
01963                     // volume column tone portamento (Mxy)
01964                     if ((ch.mEffectType == 0x3) || (ch.mEffectType == 0x5))
01965                     {
01966                         if (ch.mOldPeriod != 0)
01967                         {
01968                             if (ch.mDestPeriod > ch.mPeriod)
01969                             {
01970                                 ch.mPeriod += (ch.mTonePortamentoV * 4);
01971                                 if (ch.mPeriod > ch.mDestPeriod) ch.mPeriod = ch.mDestPeriod;
01972                             }
01973                             else if (ch.mDestPeriod < ch.mPeriod)
01974                             {
01975                                 ch.mPeriod -= (ch.mTonePortamentoV * 4);
01976                                 if (ch.mPeriod < ch.mDestPeriod) ch.mPeriod = ch.mDestPeriod;
01977                             }
01978 
01979                             ch.mBasePeriod = ch.mPeriod;
01980                         }
01981                     }
01982 
01983                     // Volume slide (Axy) / 
01984                     // tone portamento + volume slide (5xy) / 
01985                     // vibrato + volume slide (6xy)
01986                     if ((ch.mEffectType == 0xA) || (ch.mEffectType == 0x5) || (ch.mEffectType == 0x6))
01987                     {
01988                         ch.mVolume += (ch.mVolumeSlideV >> 4);
01989                         if (ch.mVolume > 0x40) ch.mVolume = 0x40;
01990 
01991                         ch.mVolume -= (ch.mVolumeSlideV & 0xF);
01992                         if (ch.mVolume < 0) ch.mVolume = 0;
01993 
01994                         ch.mBaseVolume = ch.mVolume;
01995                     }
01996 
01997                     // Vibrato
01998                     if (ch.mIsVibrato)
01999                     {
02000                         if (ch.mVibratoWaveform & WAVEFORM_SINEWAVE)
02001                             vibratoTable = mSineWaveTable;
02002                         else if (ch.mVibratoWaveform & WAVEFORM_SQUAREWAVE)
02003                             vibratoTable = mSquareWaveTable;
02004                         else if (ch.mVibratoWaveform & WAVEFORM_RAMPDOWN)
02005                             vibratoTable = mRampDownTable;
02006                         // FIX ME! Random waveform not supported
02007 
02008                         ch.mPeriod = ch.mBasePeriod + 
02009                             ((vibratoTable[ch.mVibratoPointer] * ch.mVibratoDepth) >> 7);
02010                         ch.mVibratoPointer = (UINT8)(
02011                             (ch.mVibratoPointer + ch.mVibratoRate) % XMFORMAT_SIZEOF_WAVEFORM);
02012                     }
02013                 }
02014             }
02015 
02016             for (chan = 0; chan < mSong.mNbChannels; chan++)
02017             {
02018                 XFuXMChannel &ch = mChannels[chan];
02019                 XFuXMInstrument *in = NULL;
02020 
02021                 if ((ch.mInstrumentNb != -1) && (ch.mInstrumentNb < mSong.mNbInstruments))
02022                 {
02023                     in = &mInstruments[ch.mInstrumentNb];
02024 
02025                     ch.mFinalOldVolume = ch.mFinalVolume;
02026 
02027                     // Volume envelope
02028                     if (ch.mVolEnvType & ENV_ON)
02029                     {
02030                         ch.mVolEnvValue = in->mVolumeEnvelope[ch.mVolEnvPointer];
02031 
02032                         if ((ch.mVolEnvType & ENV_SUSTAIN) && 
02033                             (ch.mVolEnvPointer == ch.mVolEnvSustain) &&
02034                             (ch.mSustainReleased == 0))
02035                         {
02036                             // Sustain point, stop envelope
02037                             ch.mVolEnvSpeed = 0;
02038                         }
02039 
02040                         // Fix for trackers which don't follow FT2 standard in envelopes
02041                         if (in->mVolEnvEnd != 0) ch.mVolEnvPointer += ch.mVolEnvSpeed;
02042 
02043                         if (ch.mVolEnvType & ENV_LOOP)
02044                         {
02045                             // Envelope loop
02046                             if (ch.mVolEnvPointer == ch.mVolEnvLoopEnd)
02047                                 ch.mVolEnvPointer = ch.mVolEnvLoopStart;
02048                         }
02049                         else
02050                         {
02051                             if (ch.mVolEnvPointer == in->mVolEnvEnd)
02052                                 ch.mVolEnvSpeed = 0;
02053                         }
02054 
02055                         if (ch.mSustainReleased)
02056                         {
02057                             ch.mVolumeFadeoutValue -= (ch.mVolumeFadeout * 2);
02058                             if (ch.mVolumeFadeoutValue < 0) ch.mVolumeFadeoutValue = 0;
02059                         }
02060                     } else ch.mVolEnvValue = REALf(1.0f); // No volume envelope
02061 
02062                     // Panning envelope
02063                     if (ch.mPanEnvType)
02064                     {
02065                         ch.mPanEnvValue = in->mPanningEnvelope[ch.mPanEnvPointer];
02066 
02067                         if ((ch.mPanEnvType & ENV_SUSTAIN) && 
02068                             (ch.mPanEnvPointer == ch.mPanEnvSustain) &&
02069                             (ch.mSustainReleased == 0))
02070                         {
02071                             // Sustain point, stop envelope
02072                             ch.mPanEnvSpeed = 0;
02073                         }
02074 
02075                         // Fix for trackers which don't follow FT2 standard in envelopes
02076                         if (in->mPanEnvEnd != 0) ch.mPanEnvPointer += ch.mPanEnvSpeed;
02077 
02078                         if (ch.mPanEnvType & ENV_LOOP)
02079                         {
02080                             // Envelope loop
02081                             if (ch.mPanEnvPointer == ch.mPanEnvLoopEnd)
02082                                 ch.mPanEnvPointer = ch.mPanEnvLoopStart;
02083                         }
02084                         else
02085                         {
02086                             if (ch.mPanEnvPointer == in->mPanEnvEnd) ch.mPanEnvSpeed = 0;
02087                         }
02088                     } else ch.mPanEnvValue = 0x20;  // No panning envelope
02089 
02090                     if (ch.mVolume > 0x40) ch.mVolume = 0x40;
02091                     if (ch.mVolume < 0) ch.mVolume = 0;
02092 
02093                     INT32 intVolume = (ch.mVolume * mSong.mGlobalVolume);
02094                     REAL volumeTemp;
02095                     volumeTemp.mValue = (intVolume << 3) + (intVolume << 1);
02096                     ch.mFinalVolume = (volumeTemp * ch.mVolEnvValue * ch.mVolumeFadeoutValue);
02097                     
02098                     volumeTemp = (ch.mFinalVolume - ch.mFinalOldVolume);
02099                     ch.mFinalVolumeSpeed = (volumeTemp * mVolumeRampDivOpt);
02100                     
02101 /*
02102                     REAL volumeTemp;
02103                     volumeTemp.mValue = (ch.mVolume * mSong.mGlobalVolume * ch.mVolumeFadeoutValue) >> 13;
02104                     ch.mFinalVolume = (volumeTemp * ch.mVolEnvValue);
02105 
02106                     volumeTemp = (ch.mFinalVolume - ch.mFinalOldVolume);
02107                     ch.mFinalVolumeSpeed = (volumeTemp * mVolumeRampDivOpt);
02108 */
02109 /*
02110                     FLOAT32 volumeReal;
02111                     volumeReal = (((FLOAT32)ch.mVolume / 65.0f) * (FLOAT32)ch.mVolEnvValue * 
02112                         (FLOAT32)ch.mVolumeFadeoutValue * ((FLOAT32)mSong.mGlobalVolume / 65.0f));
02113                     
02114                     ch.mFinalVolume = REALf(volumeReal);
02115                     
02116                     ch.mFinalVolumeSpeed = (ch.mFinalVolume - ch.mFinalOldVolume) / REALf(32);
02117 */                    
02118 /*
02119                     volumeReal = (ch.mVolume * (FLOAT32)ch.mVolEnvValue *
02120                         ch.mVolumeFadeoutValue * mSong.mGlobalVolume) *
02121                         VOLUME_DIV_OPT;
02122 
02123                     ch.mFinalVolume = (INT32)volumeReal;
02124 
02125                     ch.mFinalVolumeSpeed = (INT32)((ch.mFinalVolume - ch.mFinalOldVolume) *
02126                         VOLUME_RAMP_WIDTH_OPT);
02127 */
02128                     
02129                     ch.mFinalPan = (INT16)(ch.mPan + (((ch.mPanEnvValue - 0x20) *
02130                           (0x80 - ABS(ch.mPan - 0x80))) >> 5));
02131                     if (ch.mFinalPan > 0xFF) ch.mFinalPan = 0xFF;
02132                     else if (ch.mFinalPan < 0) ch.mFinalPan = 0;
02133 
02134                     ch.mSpeed = getSpeed(ch.mPeriod, mSampleRate);
02135                 }
02136             }
02137         }
02138 
02139         ticksLeft = (mSamplesPerTick - mSamplePointer);
02140         indicesLeft = (aSamples - index);
02141 
02142         if (ticksLeft < indicesLeft) samplesToRender = ticksLeft;
02143         else samplesToRender = indicesLeft;
02144 
02145         INT startChan = 0;
02146         INT endChan = mSong.mNbChannels;
02147         if (mFlags & XFCAUDIO_16BIT)    // 16bit
02148         {
02149             if (mFlags & XFCAUDIO_STEREO)   // 16bit stereo
02150             {
02151                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
02152                 {
02153                     cLeft = cRight = 0;
02154 
02155                     for (chan = startChan; chan < endChan; chan++)
02156                     {
02157                         XFuXMChannel &ch = mChannels[chan];
02158 
02159                         if (ch.mIsSample)
02160                         {
02161                             delta = ch.mPointer & (FP_VALUE - 1);
02162 
02163                             val1 = 0;
02164                             val2 = 0;
02165 
02166                             if (ch.mCurrentSample.m16Bit)
02167                             {
02168                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02169 
02170                                 if (ch.mLoop == 0)
02171                                 {
02172                                     interpolateLinear16(ch, val1, val2);
02173                                     addPointer(ch);
02174                                 }
02175                                 else
02176                                 {
02177                                     temp = (ch.mPointer + FP_VALUE);
02178 
02179                                     if (ch.mLoop == LOOP_FORWARD)
02180                                     {
02181                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
02182                                         addPointerForwardLoop(ch);
02183                                     }
02184                                     else if (ch.mLoop == LOOP_PINGPONG)
02185                                     {
02186                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
02187                                         addPointerBidirectionalLoop(ch);
02188                                     }
02189                                 }
02190                             }
02191                             else
02192                             {
02193                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02194 
02195                                 if (ch.mLoop == 0)
02196                                 {
02197                                     interpolateLinear8(ch, val1, val2);
02198                                     addPointer(ch);
02199                                 }
02200                                 else
02201                                 {
02202                                     temp = (ch.mPointer + FP_VALUE);
02203 
02204                                     if (ch.mLoop == LOOP_FORWARD)
02205                                     {
02206                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
02207                                         addPointerForwardLoop(ch);
02208                                     }
02209                                     else if (ch.mLoop == LOOP_PINGPONG)
02210                                     {
02211                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
02212                                         addPointerBidirectionalLoop(ch);
02213                                     }
02214                                 }
02215 
02216                                 val1 <<= 8;
02217                                 val2 <<= 8;
02218                             }
02219 
02220                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
02221 
02222                             value = (INT16)(value * ch.mFinalOldVolume);
02223                             cLeft += ((value * (0xFF - (UINT8)ch.mFinalPan)) >> 8);
02224                             cRight += ((value * (UINT8)ch.mFinalPan) >> 8);
02225 
02226                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
02227                         }
02228                     }
02229 
02230                     if (cLeft < -32768) cLeft = -32768;
02231                     else if (cLeft > 32767) cLeft = 32767;
02232                     if (cRight < -32768) cRight = -32768;
02233                     else if (cRight > 32767) cRight = 32767;
02234 
02235                     *((INT16 *)aBuf + (index << 1)) = (INT16)(cLeft ^ mTgtXor);
02236                     *((INT16 *)aBuf + (index << 1) + 1) = (INT16)(cRight ^ mTgtXor);
02237 
02238                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
02239                 }
02240             }
02241             else    // 16bit mono
02242             {
02243                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
02244                 {
02245                     c = 0;
02246 
02247                     for (chan = startChan; chan < endChan; chan++)
02248                     {
02249                         XFuXMChannel &ch = mChannels[chan];
02250 
02251                         if (ch.mIsSample)
02252                         {
02253                             delta = ch.mPointer & (FP_VALUE - 1);
02254 
02255                             val1 = 0;
02256                             val2 = 0;
02257 
02258                             if (ch.mCurrentSample.m16Bit)
02259                             {
02260                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02261 
02262                                 if (ch.mLoop == 0)
02263                                 {
02264                                     interpolateLinear16(ch, val1, val2);
02265                                     addPointer(ch);
02266                                 }
02267                                 else
02268                                 {
02269                                     temp = (ch.mPointer + FP_VALUE);
02270 
02271                                     if (ch.mLoop == LOOP_FORWARD)
02272                                     {
02273                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
02274                                         addPointerForwardLoop(ch);
02275                                     }
02276                                     else if (ch.mLoop == LOOP_PINGPONG)
02277                                     {
02278                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
02279                                         addPointerBidirectionalLoop(ch);
02280                                     }
02281                                 }
02282                             }
02283                             else
02284                             {
02285                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02286 
02287                                 if (ch.mLoop == 0)
02288                                 {
02289                                     interpolateLinear8(ch, val1, val2);
02290                                     addPointer(ch);
02291                                 }
02292                                 else
02293                                 {
02294                                     temp = (ch.mPointer + FP_VALUE);
02295 
02296                                     if (ch.mLoop == LOOP_FORWARD)
02297                                     {
02298                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
02299                                         addPointerForwardLoop(ch);
02300                                     }
02301                                     else if (ch.mLoop == LOOP_PINGPONG)
02302                                     {
02303                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
02304                                         addPointerBidirectionalLoop(ch);
02305                                     }
02306                                 }
02307 
02308                                 val1 <<= 8;
02309                                 val2 <<= 8;
02310                             }
02311 
02312                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
02313 
02314                             c += (INT16)(value * ch.mFinalOldVolume);
02315 
02316                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
02317                         }
02318                     }
02319 
02320                     if (c > 32767) c = 32767;
02321                     else if (c < -32768) c = -32768;
02322 
02323                     *((INT16 *)aBuf + index) = (INT16)(c ^ mTgtXor);
02324 
02325                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
02326                 }
02327             }
02328         }
02329         else    // 8bit
02330         {
02331             if (mFlags & XFCAUDIO_STEREO)   // 8bit stereo
02332             {
02333                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
02334                 {
02335                     cLeft = cRight = 0;
02336 
02337                     for (chan = startChan; chan < endChan; chan++)
02338                     {
02339                         XFuXMChannel &ch = mChannels[chan];
02340 
02341                         if (ch.mIsSample)
02342                         {
02343                             delta = ch.mPointer & (FP_VALUE - 1);
02344 
02345                             val1 = 0;
02346                             val2 = 0;
02347 
02348                             if (ch.mCurrentSample.m16Bit)
02349                             {
02350                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02351 
02352                                 if (ch.mLoop == 0)
02353                                 {
02354                                     interpolateLinear16(ch, val1, val2);
02355                                     addPointer(ch);
02356                                 }
02357                                 else
02358                                 {
02359                                     temp = (ch.mPointer + FP_VALUE);
02360 
02361                                     if (ch.mLoop == LOOP_FORWARD)
02362                                     {
02363                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
02364                                         addPointerForwardLoop(ch);
02365                                     }
02366                                     else if (ch.mLoop == LOOP_PINGPONG)
02367                                     {
02368                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
02369                                         addPointerBidirectionalLoop(ch);
02370                                     }
02371                                 }
02372 
02373                                 val1 >>= 8;
02374                                 val2 >>= 8;
02375                             }
02376                             else
02377                             {
02378                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02379 
02380                                 if (ch.mLoop == 0)
02381                                 {
02382                                     interpolateLinear8(ch, val1, val2);
02383                                     addPointer(ch);
02384                                 }
02385                                 else
02386                                 {
02387                                     temp = (ch.mPointer + FP_VALUE);
02388 
02389                                     if (ch.mLoop == LOOP_FORWARD)
02390                                     {
02391                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
02392                                         addPointerForwardLoop(ch);
02393                                     }
02394                                     else if (ch.mLoop == LOOP_PINGPONG)
02395                                     {
02396                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
02397                                         addPointerBidirectionalLoop(ch);
02398                                     }
02399                                 }
02400                             }
02401 
02402                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
02403 
02404                             value = (INT8)(value * ch.mFinalOldVolume);
02405                             cLeft += ((value * (0xFF - (UINT8)ch.mFinalPan)) >> 8);
02406                             cRight += ((value * (UINT8)ch.mFinalPan) >> 8);
02407 
02408                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
02409                         }
02410                     }
02411 
02412                     if (cLeft < -128) cLeft = -128;
02413                     else if (cLeft > 127) cLeft = 127;
02414                     if (cRight < -128) cRight = -128;
02415                     else if (cRight > 127) cRight = 127;
02416 
02417                     *((INT8 *)aBuf + (index << 1)) = (INT8)(cLeft ^ mTgtXor);
02418                     *((INT8 *)aBuf + (index << 1) + 1) = (INT8)(cRight ^ mTgtXor);
02419 
02420                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
02421                 }
02422             }
02423             else    // 8bit mono
02424             {
02425                 for (counter = 0; counter < samplesToRender; ++counter, ++index)
02426                 {
02427                     c = 0;
02428 
02429                     for (chan = startChan; chan < endChan; chan++)
02430                     {
02431                         XFuXMChannel &ch = mChannels[chan];
02432 
02433                         if (ch.mIsSample)
02434                         {
02435                             delta = ch.mPointer & (FP_VALUE - 1);
02436 
02437                             val1 = 0;
02438                             val2 = 0;
02439 
02440                             if (ch.mCurrentSample.m16Bit)
02441                             {
02442                                 val1 = *((INT16 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02443 
02444                                 if (ch.mLoop == 0)
02445                                 {
02446                                     interpolateLinear16(ch, val1, val2);
02447                                     addPointer(ch);
02448                                 }
02449                                 else
02450                                 {
02451                                     temp = (ch.mPointer + FP_VALUE);
02452 
02453                                     if (ch.mLoop == LOOP_FORWARD)
02454                                     {
02455                                         interpolateLinearForwardLoop16(ch, val1, val2, temp);
02456                                         addPointerForwardLoop(ch);
02457                                     }
02458                                     else if (ch.mLoop == LOOP_PINGPONG)
02459                                     {
02460                                         interpolateLinearBidirectionalLoop16(ch, val1, val2, temp);
02461                                         addPointerBidirectionalLoop(ch);
02462                                     }
02463                                 }
02464 
02465                                 val1 >>= 8;
02466                                 val2 >>= 8;
02467                             }
02468                             else
02469                             {
02470                                 val1 = *((INT8 *)ch.mOffset + (ch.mPointer >> FP_BITS));
02471 
02472                                 if (ch.mLoop == 0)
02473                                 {
02474                                     interpolateLinear8(ch, val1, val2);
02475                                     addPointer(ch);
02476                                 }
02477                                 else
02478                                 {
02479                                     temp = (ch.mPointer + FP_VALUE);
02480 
02481                                     if (ch.mLoop == LOOP_FORWARD)
02482                                     {
02483                                         interpolateLinearForwardLoop8(ch, val1, val2, temp);
02484                                         addPointerForwardLoop(ch);
02485                                     }
02486                                     else if (ch.mLoop == LOOP_PINGPONG)
02487                                     {
02488                                         interpolateLinearBidirectionalLoop8(ch, val1, val2, temp);
02489                                         addPointerBidirectionalLoop(ch);
02490                                     }
02491                                 }
02492                             }
02493 
02494                             value = (((val2 * delta) + (val1 * (FP_VALUE - delta))) >> FP_BITS);
02495 
02496                             c += (INT8)(value * ch.mFinalOldVolume);
02497 
02498                             if (mRamp < VOLUME_RAMP_WIDTH) ch.mFinalOldVolume += ch.mFinalVolumeSpeed;
02499                         }
02500                     }
02501 
02502                     if (c > 127) c = 127;
02503                     else if (c < -128) c = -128;
02504 
02505                     *((INT8 *)aBuf + index) = (INT8)(c ^ mTgtXor);
02506 
02507                     if (mRamp < VOLUME_RAMP_WIDTH) mRamp++;
02508                 }
02509             }
02510         }
02511 
02512         mSamplePointer += (samplesToRender - 1);
02513     }
02514 
02515     mTotalTicks += aSamples;
02516 
02517     return 1;
02518 }
02519 
02520 // For MSVC
02521 #pragma warning(default:4244)
02522 
02523 
02524 XFuXMPlayer::XFuXMPlayer(FLOAT32 aSampleRate, UINT32 aFlags)
02525 {
02526     mSampleRate = aSampleRate;
02527     mFlags = aFlags;
02528 
02529     mTgtXor = 0;
02530     if (!(mFlags & XFCAUDIO_SIGNED))
02531     {
02532         if (mFlags & XFCAUDIO_16BIT) mTgtXor = -32768;
02533         else mTgtXor = -128;
02534     }
02535 
02536     /* Sinewave table */
02537     mSineWaveTable[0] = 0;
02538     mSineWaveTable[1] = 24;
02539     mSineWaveTable[2] = 49;
02540     mSineWaveTable[3] = 74;
02541     mSineWaveTable[4] = 97;
02542     mSineWaveTable[5] = 120;
02543     mSineWaveTable[6] = 141;
02544     mSineWaveTable[7] = 161;
02545     mSineWaveTable[8] = 180;
02546     mSineWaveTable[9] = 197;
02547     mSineWaveTable[10] = 212;
02548     mSineWaveTable[11] = 224;
02549     mSineWaveTable[12] = 235;
02550     mSineWaveTable[13] = 244;
02551     mSineWaveTable[14] = 250;
02552     mSineWaveTable[15] = 253;
02553     mSineWaveTable[16] = 255;
02554     mSineWaveTable[17] = 253;
02555     mSineWaveTable[18] = 250;
02556     mSineWaveTable[19] = 244;
02557     mSineWaveTable[20] = 235;
02558     mSineWaveTable[21] = 224;
02559     mSineWaveTable[22] = 212;
02560     mSineWaveTable[23] = 197;
02561     mSineWaveTable[24] = 180;
02562     mSineWaveTable[25] = 161;
02563     mSineWaveTable[26] = 141;
02564     mSineWaveTable[27] = 120;
02565     mSineWaveTable[28] = 97;
02566     mSineWaveTable[29] = 74;
02567     mSineWaveTable[30] = 49;
02568     mSineWaveTable[31] = 24;
02569 
02570     INT i;
02571 
02572     for (i = 32; i < 64; i++)
02573     {
02574         mSineWaveTable[i] = (INT16)-mSineWaveTable[i - 32];
02575     }
02576 
02577     /* Squarewave table */
02578     for (i = 0; i < 32; i++) mSquareWaveTable[i] = -255;
02579     for (i = 32; i < 64; i++) mSquareWaveTable[i] = 255;
02580 
02581     /* Ramp up/down tables */
02582     for (i = 0; i < 32; i++)
02583     {
02584         mRampUpTable[i] = (INT16)(255.0f - (FLOAT32)i * (510.0f / 32.0f));
02585         mRampUpTable[i + 32] = (INT16)(255.0f - (FLOAT32)i * (510.0f / 32.0f));
02586 
02587         mRampDownTable[i] = (INT16)(-255.0f + (FLOAT32)i * (510.0f / 32.0f));
02588         mRampDownTable[i + 32] =
02589             (INT16)(-255.0f + (FLOAT32)i * (510.0f / 32.0f));
02590     }
02591 
02592     mSong.mOrderTable = NULL;
02593     mXMPatternHeaders = NULL;
02594     mPatternData = NULL;
02595     mInstruments = NULL;
02596     mChannels = NULL;
02597 
02598     mEventHandlers = NULL;
02599 }
02600 
02601 
02602 XFuXMPlayer::~XFuXMPlayer()
02603 {
02604     INT i, j;
02605 
02606     delete[] mSong.mOrderTable;
02607 
02608     delete[] mXMPatternHeaders;
02609 
02610     if (mPatternData != NULL)
02611     {
02612         for (i = 0; i < mSong.mNbPatterns; i++)
02613         {
02614             delete[] mPatternData[i].mData;
02615             delete[] mPatternData[i].mRows;
02616         }
02617 
02618         delete[] mPatternData;
02619     }
02620 
02621     if (mInstruments != NULL)
02622     {
02623         for (i = 0; i < mSong.mNbInstruments; i++)
02624         {
02625             XFuXMInstrument &ins = mInstruments[i];
02626 
02627             if (ins.mSamples != NULL)
02628             {
02629                 for (j = 0; j < ins.mNbSamples; j++)
02630                 {
02631                     delete[] (INT8 *)ins.mSamples[j].mOffset;
02632                 }
02633 
02634                 delete[] ins.mSamples;
02635             }
02636         }
02637 
02638         delete[] mInstruments;
02639     }
02640 
02641     delete[] mChannels;
02642 
02643     delete mEventHandlers;
02644 }
02645 
02646 
02647 XFuXMPlayer * XFuXMPlayer::create(const CHAR *aTunename,
02648                                   FLOAT32 aSampleRate, UINT32 aFlags)
02649 {
02650     XFcFile *textout = NULL;
02651 
02652     XFuXMPlayer *pl = new XFuXMPlayer(aSampleRate, aFlags);
02653 
02654     if (pl != NULL)
02655     {
02656         pl->initialize(aSampleRate, aFlags, 1.0, 0.5, 0);
02657 
02658         pl->mEventHandlers = new XFcLinkedList<XFuXMPlayerEventHandlerSlot>();
02659 
02660         if (pl->mEventHandlers == NULL)
02661         {
02662             delete pl;
02663             return NULL;
02664         }
02665 
02666 #ifdef OUTPUT_XM_INFO
02667         XFuXMFormatAtom ta;
02668 
02669         textout = XFcFile::open("xmoutput.txt","wt");
02670 #endif
02671 
02672         if (pl->loadXM(aTunename, textout) != 0)
02673         {
02674             // file not found
02675             delete pl;
02676             return NULL;
02677         }
02678 
02679 #ifdef OUTPUT_XM_INFO
02680         pl->dumpSongParameters(textout);
02681 
02682         pl->mPatternNb = -1;
02683         INT i;
02684         for (i = 0; i < pl->mXMHeader.mNbPatterns; i++)
02685         {
02686             pl->mPatternNb++;
02687             if (pl->mXMPatternHeaders[i].mSize > 0)
02688             {
02689                 DebugPrint(textout, "* Pattern: %02X\n", pl->mPatternNb);
02690                 {
02691                     INT row, channel;
02692                     pl->mPpoint = 0; 
02693                     for (row = 0; row < pl->mXMPatternHeaders[i].mNbRows; row++)
02694                     {
02695                         DebugPrint(textout, "%02X: ", row);
02696                         for (channel = 0; channel < pl->mXMHeader.mNbChannels; channel++)
02697                         {
02698                             ta = pl->getAtom();
02699                         
02700                             if (ta.mNote == 0)
02701                             {
02702                                 if (ta.mVolume != 0)
02703                                     DebugPrint(textout, "--- %02X %02X %1X%02X ; ",
02704                                                ta.mInstrumentNb, ta.mVolume - 0x10,
02705                                                ta.mEffectType, ta.mEffectValue);
02706                                 else
02707                                     DebugPrint(textout, "--- %02X -- %1X%02X ; ",
02708                                                ta.mInstrumentNb, ta.mEffectType,
02709                                                ta.mEffectValue);
02710                             }
02711                             else
02712                             {
02713                                 if (ta.mVolume != 0)
02714                                     DebugPrint(textout,
02715                                                "%s%1d %02X %02X %1X%02X ; ",
02716                                                notes[(ta.mNote - 1) % 12],
02717                                                (INT)((ta.mNote - 1) / 12),
02718                                                ta.mInstrumentNb, ta.mVolume - 0x10,
02719                                                ta.mEffectType, ta.mEffectValue);
02720                                 else
02721                                     DebugPrint(textout, "%s%1d %02X -- %1X%02X ; ",
02722                                                notes[(ta.mNote - 1) % 12],
02723                                                (INT)((ta.mNote - 1) / 12),
02724                                                ta.mInstrumentNb, ta.mEffectType,
02725                                                ta.mEffectValue);
02726                             }
02727                         }
02728 
02729                         DebugPrint(textout, "\n");
02730                     }
02731                 }
02732             }
02733         }
02734 
02735         if (textout != NULL) textout->close();
02736 #endif
02737 
02738         pl->initSong(0);
02739         pl->mVolumeRampDivOpt = REALf(1.0f / VOLUME_RAMP_WIDTH);
02740     }
02741 
02742     return pl;
02743 }

   
X-Forge Documentation
Confidential
Copyright © 2002-2003 Fathammer
   
Documentation generated
with doxygen
by Dimitri van Heesch